diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000..ff261bad --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,9 @@ +ARG VARIANT="3.9" +FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} + +USER vscode + +RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.44.0" RYE_INSTALL_OPTION="--yes" bash +ENV PATH=/home/vscode/.rye/shims:$PATH + +RUN echo "[[ -d .venv ]] && source .venv/bin/activate || export PATH=\$PATH" >> /home/vscode/.bashrc diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..c17fdc16 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,43 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/debian +{ + "name": "Debian", + "build": { + "dockerfile": "Dockerfile", + "context": ".." + }, + + "postStartCommand": "rye sync --all-features", + + "customizations": { + "vscode": { + "extensions": [ + "ms-python.python" + ], + "settings": { + "terminal.integrated.shell.linux": "/bin/bash", + "python.pythonPath": ".venv/bin/python", + "python.defaultInterpreterPath": ".venv/bin/python", + "python.typeChecking": "basic", + "terminal.integrated.env.linux": { + "PATH": "/home/vscode/.rye/shims:${env:PATH}" + } + } + } + }, + "features": { + "ghcr.io/devcontainers/features/node:1": {} + } + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..30235252 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,98 @@ +name: CI +on: + push: + branches-ignore: + - 'generated' + - 'codegen/**' + - 'integrated/**' + - 'stl-preview-head/**' + - 'stl-preview-base/**' + pull_request: + branches-ignore: + - 'stl-preview-head/**' + - 'stl-preview-base/**' + +jobs: + lint: + timeout-minutes: 10 + name: lint + runs-on: ${{ github.repository == 'stainless-sdks/gcore-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + steps: + - uses: actions/checkout@v6 + + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Install dependencies + run: rye sync --all-features + + - name: Run lints + run: ./scripts/lint + + build: + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + timeout-minutes: 10 + name: build + permissions: + contents: read + id-token: write + runs-on: ${{ github.repository == 'stainless-sdks/gcore-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + steps: + - uses: actions/checkout@v6 + + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Install dependencies + run: rye sync --all-features + + - name: Run build + run: rye build + + - name: Get GitHub OIDC Token + if: github.repository == 'stainless-sdks/gcore-python' + id: github-oidc + uses: actions/github-script@v8 + with: + script: core.setOutput('github_token', await core.getIDToken()); + + - name: Upload tarball + if: github.repository == 'stainless-sdks/gcore-python' + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + run: ./scripts/utils/upload-artifact.sh + + test: + timeout-minutes: 10 + name: test + runs-on: ${{ github.repository == 'stainless-sdks/gcore-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + steps: + - uses: actions/checkout@v6 + + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Bootstrap + run: ./scripts/bootstrap + + - name: Run tests + run: ./scripts/test diff --git a/.github/workflows/detect-breaking-changes.yml b/.github/workflows/detect-breaking-changes.yml new file mode 100644 index 00000000..ffca94cc --- /dev/null +++ b/.github/workflows/detect-breaking-changes.yml @@ -0,0 +1,42 @@ +name: CI +on: + pull_request: + branches: + - main + - next + +jobs: + detect_breaking_changes: + runs-on: 'ubuntu-latest' + name: detect-breaking-changes + if: github.repository == 'G-Core/gcore-python' + steps: + - name: Calculate fetch-depth + run: | + echo "FETCH_DEPTH=$(expr ${{ github.event.pull_request.commits }} + 1)" >> $GITHUB_ENV + + - uses: actions/checkout@v6 + with: + # Ensure we can check out the pull request base in the script below. + fetch-depth: ${{ env.FETCH_DEPTH }} + + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + - name: Install dependencies + run: | + rye sync --all-features + - name: Detect removed symbols + run: | + rye run python scripts/detect-breaking-changes.py "${{ github.event.pull_request.base.sha }}" + + - name: Detect breaking changes + run: | + # Try to check out previous versions of the breaking change detection script. This ensures that + # we still detect breaking changes when entire files and their tests are removed. + git checkout "${{ github.event.pull_request.base.sha }}" -- ./scripts/detect-breaking-changes 2>/dev/null || true + ./scripts/detect-breaking-changes ${{ github.event.pull_request.base.sha }} \ No newline at end of file diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml new file mode 100644 index 00000000..3cebca63 --- /dev/null +++ b/.github/workflows/publish-pypi.yml @@ -0,0 +1,31 @@ +# This workflow is triggered when a GitHub release is created. +# It can also be run manually to re-publish to PyPI in case it failed for some reason. +# You can run this workflow by navigating to https://www.github.com/G-Core/gcore-python/actions/workflows/publish-pypi.yml +name: Publish PyPI +on: + workflow_dispatch: + + release: + types: [published] + +jobs: + publish: + name: publish + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Publish to PyPI + run: | + bash ./bin/publish-pypi + env: + PYPI_TOKEN: ${{ secrets.GCORE_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml new file mode 100644 index 00000000..927bb62a --- /dev/null +++ b/.github/workflows/release-doctor.yml @@ -0,0 +1,21 @@ +name: Release Doctor +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + release_doctor: + name: release doctor + runs-on: ubuntu-latest + if: github.repository == 'G-Core/gcore-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') + + steps: + - uses: actions/checkout@v6 + + - name: Check release environment + run: | + bash ./bin/check-release-environment + env: + PYPI_TOKEN: ${{ secrets.GCORE_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..95ceb189 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +.prism.log +_dev + +__pycache__ +.mypy_cache + +dist + +.venv +.idea + +.env +.envrc +codegen.log +Brewfile.lock.json diff --git a/.python-version b/.python-version new file mode 100644 index 00000000..43077b24 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.9.18 diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 00000000..57dc0c3d --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.33.0" +} \ No newline at end of file diff --git a/.stats.yml b/.stats.yml new file mode 100644 index 00000000..54d04e2d --- /dev/null +++ b/.stats.yml @@ -0,0 +1,4 @@ +configured_endpoints: 645 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore%2Fgcore-30f92b095e6f90731f4e7652affc69f27c57849dccf30119b79c26314aa2ae00.yml +openapi_spec_hash: 2348a329bec98d05bf5e4c109d300382 +config_hash: bc578a7de14c42e33b7d4bd4502218f2 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..5b010307 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.analysis.importFormat": "relative", +} diff --git a/Brewfile b/Brewfile new file mode 100644 index 00000000..492ca37b --- /dev/null +++ b/Brewfile @@ -0,0 +1,2 @@ +brew "rye" + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..be330c39 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,128 @@ +## Setting up the environment + +### With Rye + +We use [Rye](https://rye.astral.sh/) to manage dependencies because it will automatically provision a Python environment with the expected Python version. To set it up, run: + +```sh +$ ./scripts/bootstrap +``` + +Or [install Rye manually](https://rye.astral.sh/guide/installation/) and run: + +```sh +$ rye sync --all-features +``` + +You can then run scripts using `rye run python script.py` or by activating the virtual environment: + +```sh +# Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work +$ source .venv/bin/activate + +# now you can omit the `rye run` prefix +$ python script.py +``` + +### Without Rye + +Alternatively if you don't want to install `Rye`, you can stick with the standard `pip` setup by ensuring you have the Python version specified in `.python-version`, create a virtual environment however you desire and then install dependencies using this command: + +```sh +$ pip install -r requirements-dev.lock +``` + +## Modifying/Adding code + +Most of the SDK is generated code. Modifications to code will be persisted between generations, but may +result in merge conflicts between manual patches and changes from the generator. The generator will never +modify the contents of the `src/gcore/lib/` and `examples/` directories. + +## Adding and running examples + +All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. + +```py +# add an example to examples/.py + +#!/usr/bin/env -S rye run python +… +``` + +```sh +$ chmod +x examples/.py +# run the example against your api +$ ./examples/.py +``` + +## Using the repository from source + +If you’d like to use the repository from source, you can either install from git or link to a cloned repository: + +To install via git: + +```sh +$ pip install git+ssh://git@github.com/G-Core/gcore-python.git +``` + +Alternatively, you can build from source and install the wheel file: + +Building this package will create two files in the `dist/` directory, a `.tar.gz` containing the source files and a `.whl` that can be used to install the package efficiently. + +To create a distributable version of the library, all you have to do is run this command: + +```sh +$ rye build +# or +$ python -m build +``` + +Then to install: + +```sh +$ pip install ./path-to-wheel-file.whl +``` + +## Running tests + +Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. + +```sh +# you will need npm installed +$ npx prism mock path/to/your/openapi.yml +``` + +```sh +$ ./scripts/test +``` + +## Linting and formatting + +This repository uses [ruff](https://github.com/astral-sh/ruff) and +[black](https://github.com/psf/black) to format the code in the repository. + +To lint: + +```sh +$ ./scripts/lint +``` + +To format and fix all ruff issues automatically: + +```sh +$ ./scripts/format +``` + +## Publishing and releases + +Changes made to this repository via the automated release PR pipeline should publish to PyPI automatically. If +the changes aren't made through the automated pipeline, you may want to make releases manually. + +### Publish with a GitHub workflow + +You can release to package managers by using [the `Publish PyPI` GitHub action](https://www.github.com/G-Core/gcore-python/actions/workflows/publish-pypi.yml). This requires a setup organization or repository secret to be set up. + +### Publish manually + +If you need to manually release a package, you can run the `bin/publish-pypi` script with a `PYPI_TOKEN` set on +the environment. diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..03c99139 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2026 Gcore + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 6043a36e..e33c80e6 100644 --- a/README.md +++ b/README.md @@ -1 +1,453 @@ -# gcore-python \ No newline at end of file +# Gcore Python API library + + +[![PyPI version](https://img.shields.io/pypi/v/gcore.svg?label=pypi%20(stable))](https://pypi.org/project/gcore/) + +The Gcore Python library provides convenient access to the Gcore REST API from any Python 3.9+ +application. The library includes type definitions for all request params and response fields, +and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx). + +It is generated with [Stainless](https://www.stainless.com/). + +## Documentation + +The REST API documentation can be found on [api.gcore.com](https://api.gcore.com/docs). The full API of this library can be found in [api.md](api.md). + +## Installation + +```sh +# install from PyPI +pip install gcore +``` + +## Usage + +The full API of this library can be found in [api.md](api.md). + +```python +import os +from gcore import Gcore + +client = Gcore( + api_key=os.environ.get("GCORE_API_KEY"), # This is the default and can be omitted +) + +project = client.cloud.projects.create( + name="my-project", +) +print(project.id) +``` + +While you can provide an `api_key` keyword argument, +we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) +to add `GCORE_API_KEY="My API Key"` to your `.env` file +so that your API Key is not stored in source control. + +## Async usage + +Simply import `AsyncGcore` instead of `Gcore` and use `await` with each API call: + +```python +import os +import asyncio +from gcore import AsyncGcore + +client = AsyncGcore( + api_key=os.environ.get("GCORE_API_KEY"), # This is the default and can be omitted +) + + +async def main() -> None: + project = await client.cloud.projects.create( + name="my-project", + ) + print(project.id) + + +asyncio.run(main()) +``` + +Functionality between the synchronous and asynchronous clients is otherwise identical. + +### With aiohttp + +By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend. + +You can enable this by installing `aiohttp`: + +```sh +# install from PyPI +pip install gcore[aiohttp] +``` + +Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: + +```python +import os +import asyncio +from gcore import DefaultAioHttpClient +from gcore import AsyncGcore + + +async def main() -> None: + async with AsyncGcore( + api_key=os.environ.get("GCORE_API_KEY"), # This is the default and can be omitted + http_client=DefaultAioHttpClient(), + ) as client: + project = await client.cloud.projects.create( + name="my-project", + ) + print(project.id) + + +asyncio.run(main()) +``` + +## Using types + +Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like: + +- Serializing back into JSON, `model.to_json()` +- Converting to a dictionary, `model.to_dict()` + +Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`. + +## Pagination + +List methods in the Gcore API are paginated. + +This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually: + +```python +from gcore import Gcore + +client = Gcore() + +all_projects = [] +# Automatically fetches more pages as needed. +for project in client.cloud.projects.list( + limit=10, + offset=0, +): + # Do something with project here + all_projects.append(project) +print(all_projects) +``` + +Or, asynchronously: + +```python +import asyncio +from gcore import AsyncGcore + +client = AsyncGcore() + + +async def main() -> None: + all_projects = [] + # Iterate through items across all pages, issuing requests as needed. + async for project in client.cloud.projects.list( + limit=10, + offset=0, + ): + all_projects.append(project) + print(all_projects) + + +asyncio.run(main()) +``` + +Alternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages: + +```python +first_page = await client.cloud.projects.list( + limit=10, + offset=0, +) +if first_page.has_next_page(): + print(f"will fetch next page using these details: {first_page.next_page_info()}") + next_page = await first_page.get_next_page() + print(f"number of items we just fetched: {len(next_page.results)}") + +# Remove `await` for non-async usage. +``` + +Or just work directly with the returned data: + +```python +first_page = await client.cloud.projects.list( + limit=10, + offset=0, +) +for project in first_page.results: + print(project.id) + +# Remove `await` for non-async usage. +``` + +## Handling errors + +When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `gcore.APIConnectionError` is raised. + +When the API returns a non-success status code (that is, 4xx or 5xx +response), a subclass of `gcore.APIStatusError` is raised, containing `status_code` and `response` properties. + +All errors inherit from `gcore.APIError`. + +```python +import gcore +from gcore import Gcore + +client = Gcore() + +try: + client.cloud.projects.create( + name="my-project", + ) +except gcore.APIConnectionError as e: + print("The server could not be reached") + print(e.__cause__) # an underlying Exception, likely raised within httpx. +except gcore.RateLimitError as e: + print("A 429 status code was received; we should back off a bit.") +except gcore.APIStatusError as e: + print("Another non-200-range status code was received") + print(e.status_code) + print(e.response) +``` + +Error codes are as follows: + +| Status Code | Error Type | +| ----------- | -------------------------- | +| 400 | `BadRequestError` | +| 401 | `AuthenticationError` | +| 403 | `PermissionDeniedError` | +| 404 | `NotFoundError` | +| 422 | `UnprocessableEntityError` | +| 429 | `RateLimitError` | +| >=500 | `InternalServerError` | +| N/A | `APIConnectionError` | + +### Retries + +Certain errors are automatically retried 2 times by default, with a short exponential backoff. +Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, +429 Rate Limit, and >=500 Internal errors are all retried by default. + +You can use the `max_retries` option to configure or disable retry settings: + +```python +from gcore import Gcore + +# Configure the default for all requests: +client = Gcore( + # default is 2 + max_retries=0, +) + +# Or, configure per-request: +client.with_options(max_retries=5).cloud.projects.create( + name="my-project", +) +``` + +### Timeouts + +By default requests time out after 2 minutes. You can configure this with a `timeout` option, +which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object: + +```python +from gcore import Gcore + +# Configure the default for all requests: +client = Gcore( + # 20 seconds (default is 2 minutes) + timeout=20.0, +) + +# More granular control: +client = Gcore( + timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0), +) + +# Override per-request: +client.with_options(timeout=5.0).cloud.projects.create( + name="my-project", +) +``` + +On timeout, an `APITimeoutError` is thrown. + +Note that requests that time out are [retried twice by default](#retries). + +## Advanced + +### Logging + +We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module. + +You can enable logging by setting the environment variable `GCORE_LOG` to `info`. + +```shell +$ export GCORE_LOG=info +``` + +Or to `debug` for more verbose logging. + +### How to tell whether `None` means `null` or missing + +In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`: + +```py +if response.my_field is None: + if 'my_field' not in response.model_fields_set: + print('Got json like {}, without a "my_field" key present at all.') + else: + print('Got json like {"my_field": null}.') +``` + +### Accessing raw response data (e.g. headers) + +The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g., + +```py +from gcore import Gcore + +client = Gcore() +response = client.cloud.projects.with_raw_response.create( + name="my-project", +) +print(response.headers.get('X-My-Header')) + +project = response.parse() # get the object that `cloud.projects.create()` would have returned +print(project.id) +``` + +These methods return an [`APIResponse`](https://github.com/G-Core/gcore-python/tree/main/src/gcore/_response.py) object. + +The async client returns an [`AsyncAPIResponse`](https://github.com/G-Core/gcore-python/tree/main/src/gcore/_response.py) with the same structure, the only difference being `await`able methods for reading the response content. + +#### `.with_streaming_response` + +The above interface eagerly reads the full response body when you make the request, which may not always be what you want. + +To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods. + +```python +with client.cloud.projects.with_streaming_response.create( + name="my-project", +) as response: + print(response.headers.get("X-My-Header")) + + for line in response.iter_lines(): + print(line) +``` + +The context manager is required so that the response will reliably be closed. + +### Making custom/undocumented requests + +This library is typed for convenient access to the documented API. + +If you need to access undocumented endpoints, params, or response properties, the library can still be used. + +#### Undocumented endpoints + +To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other +http verbs. Options on the client will be respected (such as retries) when making this request. + +```py +import httpx + +response = client.post( + "/foo", + cast_to=httpx.Response, + body={"my_param": True}, +) + +print(response.headers.get("x-foo")) +``` + +#### Undocumented request params + +If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request +options. + +#### Undocumented response properties + +To access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You +can also get all the extra fields on the Pydantic model as a dict with +[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra). + +### Configuring the HTTP client + +You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including: + +- Support for [proxies](https://www.python-httpx.org/advanced/proxies/) +- Custom [transports](https://www.python-httpx.org/advanced/transports/) +- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality + +```python +import httpx +from gcore import Gcore, DefaultHttpxClient + +client = Gcore( + # Or use the `GCORE_BASE_URL` env var + base_url="http://my.test.server.example.com:8083", + http_client=DefaultHttpxClient( + proxy="http://my.test.proxy.example.com", + transport=httpx.HTTPTransport(local_address="0.0.0.0"), + ), +) +``` + +You can also customize the client on a per-request basis by using `with_options()`: + +```python +client.with_options(http_client=DefaultHttpxClient(...)) +``` + +### Managing HTTP resources + +By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting. + +```py +from gcore import Gcore + +with Gcore() as client: + # make requests here + ... + +# HTTP client is now closed +``` + +## Versioning + +This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: + +1. Changes that only affect static types, without breaking runtime behavior. +2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ +3. Changes that we do not expect to impact the vast majority of users in practice. + +We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. + +We are keen for your feedback; please open an [issue](https://www.github.com/G-Core/gcore-python/issues) with questions, bugs, or suggestions. + +### Determining the installed version + +If you've upgraded to the latest version but aren't seeing any new features you were expecting then your python environment is likely still using an older version. + +You can determine the version that is being used at runtime with: + +```py +import gcore +print(gcore.__version__) +``` + +## Requirements + +Python 3.9 or higher. + +## Contributing + +See [the contributing documentation](./CONTRIBUTING.md). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..899ab304 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +# Security Policy + +## Reporting Security Issues + +This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. + +To report a security issue, please contact the Stainless team at security@stainless.com. + +## Responsible Disclosure + +We appreciate the efforts of security researchers and individuals who help us maintain the security of +SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible +disclosure practices by allowing us a reasonable amount of time to investigate and address the issue +before making any information public. + +## Reporting Non-SDK Related Security Issues + +If you encounter security issues that are not directly related to SDKs but pertain to the services +or products provided by Gcore, please follow the respective company's security reporting guidelines. + +### Gcore Terms and Policies + +Please contact support@gcore.com for any questions or concerns regarding the security of our services. + +--- + +Thank you for helping us keep the SDKs and systems they interact with secure. diff --git a/api.md b/api.md new file mode 100644 index 00000000..9faa9ce7 --- /dev/null +++ b/api.md @@ -0,0 +1,17 @@ +# [Cloud](src/gcore/resources/cloud/api.md) + +# [Waap](src/gcore/resources/waap/api.md) + +# [Iam](src/gcore/resources/iam/api.md) + +# [Fastedge](src/gcore/resources/fastedge/api.md) + +# [Streaming](src/gcore/resources/streaming/api.md) + +# [Security](src/gcore/resources/security/api.md) + +# [DNS](src/gcore/resources/dns/api.md) + +# [Storage](src/gcore/resources/storage/api.md) + +# [CDN](src/gcore/resources/cdn/api.md) diff --git a/bin/check-release-environment b/bin/check-release-environment new file mode 100644 index 00000000..b845b0f4 --- /dev/null +++ b/bin/check-release-environment @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +errors=() + +if [ -z "${PYPI_TOKEN}" ]; then + errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") +fi + +lenErrors=${#errors[@]} + +if [[ lenErrors -gt 0 ]]; then + echo -e "Found the following errors in the release environment:\n" + + for error in "${errors[@]}"; do + echo -e "- $error\n" + done + + exit 1 +fi + +echo "The environment is ready to push releases!" diff --git a/bin/publish-pypi b/bin/publish-pypi new file mode 100644 index 00000000..826054e9 --- /dev/null +++ b/bin/publish-pypi @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -eux +mkdir -p dist +rye build --clean +rye publish --yes --token=$PYPI_TOKEN diff --git a/examples/.keep b/examples/.keep new file mode 100644 index 00000000..d8c73e93 --- /dev/null +++ b/examples/.keep @@ -0,0 +1,4 @@ +File generated from our OpenAPI spec by Stainless. + +This directory can be used to store example files demonstrating usage of this SDK. +It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. \ No newline at end of file diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 00000000..53bca7ff --- /dev/null +++ b/noxfile.py @@ -0,0 +1,9 @@ +import nox + + +@nox.session(reuse_venv=True, name="test-pydantic-v1") +def test_pydantic_v1(session: nox.Session) -> None: + session.install("-r", "requirements-dev.lock") + session.install("pydantic<2") + + session.run("pytest", "--showlocals", "--ignore=tests/functional", *session.posargs) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..cfdfa971 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,270 @@ +[project] +name = "gcore" +version = "0.33.0" +description = "The official Python library for the gcore API" +dynamic = ["readme"] +license = "Apache-2.0" +authors = [ +{ name = "Gcore", email = "support@gcore.com" }, +] + +dependencies = [ + "httpx>=0.23.0, <1", + "pydantic>=1.9.0, <3", + "typing-extensions>=4.10, <5", + "anyio>=3.5.0, <5", + "distro>=1.7.0, <2", + "sniffio", +] + +requires-python = ">= 3.9" +classifiers = [ + "Typing :: Typed", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Operating System :: OS Independent", + "Operating System :: POSIX", + "Operating System :: MacOS", + "Operating System :: POSIX :: Linux", + "Operating System :: Microsoft :: Windows", + "Topic :: Software Development :: Libraries :: Python Modules", + "License :: OSI Approved :: Apache Software License" +] + +[project.urls] +Homepage = "https://github.com/G-Core/gcore-python" +Repository = "https://github.com/G-Core/gcore-python" + +[project.optional-dependencies] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.9"] + +[tool.rye] +managed = true +# version pins are in requirements-dev.lock +dev-dependencies = [ + "pyright==1.1.399", + "mypy==1.17", + "respx", + "pytest", + "pytest-asyncio", + "ruff", + "time-machine", + "nox", + "dirty-equals>=0.6.0", + "importlib-metadata>=6.7.0", + "rich>=13.7.1", + "pytest-xdist>=3.6.1", + "griffe>=1", +] + +[tool.rye.scripts] +format = { chain = [ + "format:ruff", + "format:docs", + "fix:ruff", + # run formatting again to fix any inconsistencies when imports are stripped + "format:ruff", +]} +"format:docs" = "bash -c 'python scripts/utils/ruffen-docs.py README.md $(find . -type f -name api.md)'" +"format:ruff" = "ruff format" + +"lint" = { chain = [ + "check:ruff", + "typecheck", + "check:importable", +]} +"check:ruff" = "ruff check ." +"fix:ruff" = "ruff check --fix ." + +"check:importable" = "python -c 'import gcore'" + +typecheck = { chain = [ + "typecheck:pyright", + "typecheck:mypy" +]} +"typecheck:pyright" = "pyright" +"typecheck:verify-types" = "pyright --verifytypes gcore --ignoreexternal" +"typecheck:mypy" = "mypy ." + +[build-system] +requires = ["hatchling==1.26.3", "hatch-fancy-pypi-readme"] +build-backend = "hatchling.build" + +[tool.hatch.build] +include = [ + "src/*" +] + +[tool.hatch.build.targets.wheel] +packages = ["src/gcore"] + +[tool.hatch.build.targets.sdist] +# Basically everything except hidden files/directories (such as .github, .devcontainers, .python-version, etc) +include = [ + "/*.toml", + "/*.json", + "/*.lock", + "/*.md", + "/mypy.ini", + "/noxfile.py", + "bin/*", + "examples/*", + "src/*", + "tests/*", +] + +[tool.hatch.metadata.hooks.fancy-pypi-readme] +content-type = "text/markdown" + +[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] +path = "README.md" + +[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]] +# replace relative links with absolute links +pattern = '\[(.+?)\]\(((?!https?://)\S+?)\)' +replacement = '[\1](https://github.com/G-Core/gcore-python/tree/main/\g<2>)' + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = "--tb=short -n auto" +xfail_strict = true +asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "session" +filterwarnings = [ + "error" +] + +[tool.pyright] +# this enables practically every flag given by pyright. +# there are a couple of flags that are still disabled by +# default in strict mode as they are experimental and niche. +typeCheckingMode = "strict" +pythonVersion = "3.9" + +exclude = [ + "_dev", + ".venv", + ".nox", + ".git", +] + +reportImplicitOverride = true +reportOverlappingOverload = false + +reportImportCycles = false +reportPrivateUsage = false + +[tool.mypy] +pretty = true +show_error_codes = true + +# Exclude _files.py because mypy isn't smart enough to apply +# the correct type narrowing and as this is an internal module +# it's fine to just use Pyright. +# +# We also exclude our `tests` as mypy doesn't always infer +# types correctly and Pyright will still catch any type errors. +exclude = ['src/gcore/_files.py', '_dev/.*.py', 'tests/.*'] + +strict_equality = true +implicit_reexport = true +check_untyped_defs = true +no_implicit_optional = true + +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true + +# Turn these options off as it could cause conflicts +# with the Pyright options. +warn_unused_ignores = false +warn_redundant_casts = false + +disallow_any_generics = true +disallow_untyped_defs = true +disallow_untyped_calls = true +disallow_subclassing_any = true +disallow_incomplete_defs = true +disallow_untyped_decorators = true +cache_fine_grained = true + +# By default, mypy reports an error if you assign a value to the result +# of a function call that doesn't return anything. We do this in our test +# cases: +# ``` +# result = ... +# assert result is None +# ``` +# Changing this codegen to make mypy happy would increase complexity +# and would not be worth it. +disable_error_code = "func-returns-value,overload-cannot-match" + +# https://github.com/python/mypy/issues/12162 +[[tool.mypy.overrides]] +module = "black.files.*" +ignore_errors = true +ignore_missing_imports = true + + +[tool.ruff] +line-length = 120 +output-format = "grouped" +target-version = "py38" + +[tool.ruff.format] +docstring-code-format = true + +[tool.ruff.lint] +select = [ + # isort + "I", + # bugbear rules + "B", + # remove unused imports + "F401", + # check for missing future annotations + "FA102", + # bare except statements + "E722", + # unused arguments + "ARG", + # print statements + "T201", + "T203", + # misuse of typing.TYPE_CHECKING + "TC004", + # import rules + "TID251", +] +ignore = [ + # mutable defaults + "B006", +] +unfixable = [ + # disable auto fix for print statements + "T201", + "T203", +] + +extend-safe-fixes = ["FA102"] + +[tool.ruff.lint.flake8-tidy-imports.banned-api] +"functools.lru_cache".msg = "This function does not retain type information for the wrapped function's arguments; The `lru_cache` function from `_utils` should be used instead" + +[tool.ruff.lint.isort] +length-sort = true +length-sort-straight = true +combine-as-imports = true +extra-standard-library = ["typing_extensions"] +known-first-party = ["gcore", "tests"] + +[tool.ruff.lint.per-file-ignores] +"bin/**.py" = ["T201", "T203"] +"scripts/**.py" = ["T201", "T203"] +"tests/**.py" = ["T201", "T203"] +"examples/**.py" = ["T201", "T203"] diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 00000000..1cc0e065 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,66 @@ +{ + "packages": { + ".": {} + }, + "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", + "include-v-in-tag": true, + "include-component-in-tag": false, + "versioning": "prerelease", + "prerelease": true, + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": false, + "pull-request-header": "Automated Release PR", + "pull-request-title-pattern": "release: ${version}", + "changelog-sections": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "chore", + "section": "Chores" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "style", + "section": "Styles" + }, + { + "type": "refactor", + "section": "Refactors" + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "build", + "section": "Build System" + }, + { + "type": "ci", + "section": "Continuous Integration", + "hidden": true + } + ], + "release-type": "python", + "extra-files": [ + "src/gcore/_version.py" + ] +} \ No newline at end of file diff --git a/requirements-dev.lock b/requirements-dev.lock new file mode 100644 index 00000000..cbc55141 --- /dev/null +++ b/requirements-dev.lock @@ -0,0 +1,152 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: true +# with-sources: false +# generate-hashes: false +# universal: false + +-e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.13.3 + # via gcore + # via httpx-aiohttp +aiosignal==1.4.0 + # via aiohttp +annotated-types==0.7.0 + # via pydantic +anyio==4.12.1 + # via gcore + # via httpx +argcomplete==3.6.3 + # via nox +async-timeout==5.0.1 + # via aiohttp +attrs==25.4.0 + # via aiohttp + # via nox +backports-asyncio-runner==1.2.0 + # via pytest-asyncio +certifi==2026.1.4 + # via httpcore + # via httpx +colorama==0.4.6 + # via griffe +colorlog==6.10.1 + # via nox +dependency-groups==1.3.1 + # via nox +dirty-equals==0.11 +distlib==0.4.0 + # via virtualenv +distro==1.9.0 + # via gcore +exceptiongroup==1.3.1 + # via anyio + # via pytest +execnet==2.1.2 + # via pytest-xdist +filelock==3.19.1 + # via virtualenv +frozenlist==1.8.0 + # via aiohttp + # via aiosignal +griffe==1.14.0 +h11==0.16.0 + # via httpcore +httpcore==1.0.9 + # via httpx +httpx==0.28.1 + # via gcore + # via httpx-aiohttp + # via respx +httpx-aiohttp==0.1.12 + # via gcore +humanize==4.13.0 + # via nox +idna==3.11 + # via anyio + # via httpx + # via yarl +importlib-metadata==8.7.1 +iniconfig==2.1.0 + # via pytest +markdown-it-py==3.0.0 + # via rich +mdurl==0.1.2 + # via markdown-it-py +multidict==6.7.0 + # via aiohttp + # via yarl +mypy==1.17.0 +mypy-extensions==1.1.0 + # via mypy +nodeenv==1.10.0 + # via pyright +nox==2025.11.12 +packaging==25.0 + # via dependency-groups + # via nox + # via pytest +pathspec==1.0.3 + # via mypy +platformdirs==4.4.0 + # via virtualenv +pluggy==1.6.0 + # via pytest +propcache==0.4.1 + # via aiohttp + # via yarl +pydantic==2.12.5 + # via gcore +pydantic-core==2.41.5 + # via pydantic +pygments==2.19.2 + # via pytest + # via rich +pyright==1.1.399 +pytest==8.4.2 + # via pytest-asyncio + # via pytest-xdist +pytest-asyncio==1.2.0 +pytest-xdist==3.8.0 +python-dateutil==2.9.0.post0 + # via time-machine +respx==0.22.0 +rich==14.2.0 +ruff==0.14.13 +six==1.17.0 + # via python-dateutil +sniffio==1.3.1 + # via gcore +time-machine==2.19.0 +tomli==2.4.0 + # via dependency-groups + # via mypy + # via nox + # via pytest +typing-extensions==4.15.0 + # via aiosignal + # via anyio + # via exceptiongroup + # via gcore + # via multidict + # via mypy + # via pydantic + # via pydantic-core + # via pyright + # via pytest-asyncio + # via typing-inspection + # via virtualenv +typing-inspection==0.4.2 + # via pydantic +virtualenv==20.36.1 + # via nox +yarl==1.22.0 + # via aiohttp +zipp==3.23.0 + # via importlib-metadata diff --git a/requirements.lock b/requirements.lock new file mode 100644 index 00000000..8fa704e1 --- /dev/null +++ b/requirements.lock @@ -0,0 +1,76 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: true +# with-sources: false +# generate-hashes: false +# universal: false + +-e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.13.3 + # via gcore + # via httpx-aiohttp +aiosignal==1.4.0 + # via aiohttp +annotated-types==0.7.0 + # via pydantic +anyio==4.12.1 + # via gcore + # via httpx +async-timeout==5.0.1 + # via aiohttp +attrs==25.4.0 + # via aiohttp +certifi==2026.1.4 + # via httpcore + # via httpx +distro==1.9.0 + # via gcore +exceptiongroup==1.3.1 + # via anyio +frozenlist==1.8.0 + # via aiohttp + # via aiosignal +h11==0.16.0 + # via httpcore +httpcore==1.0.9 + # via httpx +httpx==0.28.1 + # via gcore + # via httpx-aiohttp +httpx-aiohttp==0.1.12 + # via gcore +idna==3.11 + # via anyio + # via httpx + # via yarl +multidict==6.7.0 + # via aiohttp + # via yarl +propcache==0.4.1 + # via aiohttp + # via yarl +pydantic==2.12.5 + # via gcore +pydantic-core==2.41.5 + # via pydantic +sniffio==1.3.1 + # via gcore +typing-extensions==4.15.0 + # via aiosignal + # via anyio + # via exceptiongroup + # via gcore + # via multidict + # via pydantic + # via pydantic-core + # via typing-inspection +typing-inspection==0.4.2 + # via pydantic +yarl==1.22.0 + # via aiohttp diff --git a/scripts/bootstrap b/scripts/bootstrap new file mode 100755 index 00000000..b430fee3 --- /dev/null +++ b/scripts/bootstrap @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then + brew bundle check >/dev/null 2>&1 || { + echo -n "==> Install Homebrew dependencies? (y/N): " + read -r response + case "$response" in + [yY][eE][sS]|[yY]) + brew bundle + ;; + *) + ;; + esac + echo + } +fi + +echo "==> Installing Python dependencies…" + +# experimental uv support makes installations significantly faster +rye config --set-bool behavior.use-uv=true + +rye sync --all-features diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes new file mode 100755 index 00000000..fb28f3a2 --- /dev/null +++ b/scripts/detect-breaking-changes @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +echo "==> Detecting breaking changes" + +TEST_PATHS=( tests/api_resources tests/test_client.py tests/test_response.py ) + +for PATHSPEC in "${TEST_PATHS[@]}"; do + # Try to check out previous versions of the test files + # with the current SDK. + git checkout "$1" -- "${PATHSPEC}" 2>/dev/null || true +done + +# Instead of running the tests, use the linter to check if an +# older test is no longer compatible with the latest SDK. +./scripts/lint diff --git a/scripts/detect-breaking-changes.py b/scripts/detect-breaking-changes.py new file mode 100644 index 00000000..bc61aeaf --- /dev/null +++ b/scripts/detect-breaking-changes.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +import sys +from typing import Iterator +from pathlib import Path + +import rich +import griffe +from rich.text import Text +from rich.style import Style + + +def public_members(obj: griffe.Object | griffe.Alias) -> dict[str, griffe.Object | griffe.Alias]: + if isinstance(obj, griffe.Alias): + # ignore imports for now, they're technically part of the public API + # but we don't have good preventative measures in place to prevent + # changing them + return {} + + return {name: value for name, value in obj.all_members.items() if not name.startswith("_")} + + +def find_breaking_changes( + new_obj: griffe.Object | griffe.Alias, + old_obj: griffe.Object | griffe.Alias, + *, + path: list[str], +) -> Iterator[Text | str]: + new_members = public_members(new_obj) + old_members = public_members(old_obj) + + for name, old_member in old_members.items(): + if isinstance(old_member, griffe.Alias) and len(path) > 2: + # ignore imports in `/types/` for now, they're technically part of the public API + # but we don't have good preventative measures in place to prevent changing them + continue + + new_member = new_members.get(name) + if new_member is None: + cls_name = old_member.__class__.__name__ + yield Text(f"({cls_name})", style=Style(color="rgb(119, 119, 119)")) + yield from [" " for _ in range(10 - len(cls_name))] + yield f" {'.'.join(path)}.{name}" + yield "\n" + continue + + yield from find_breaking_changes(new_member, old_member, path=[*path, name]) + + +def main() -> None: + try: + against_ref = sys.argv[1] + except IndexError as err: + raise RuntimeError("You must specify a base ref to run breaking change detection against") from err + + package = griffe.load( + "gcore", + search_paths=[Path(__file__).parent.parent.joinpath("src")], + ) + old_package = griffe.load_git( + "gcore", + ref=against_ref, + search_paths=["src"], + ) + assert isinstance(package, griffe.Module) + assert isinstance(old_package, griffe.Module) + + output = list(find_breaking_changes(package, old_package, path=["gcore"])) + if output: + rich.print(Text("Breaking changes detected!", style=Style(color="rgb(165, 79, 87)"))) + rich.print() + + for text in output: + rich.print(text, end="") + + sys.exit(1) + + +main() diff --git a/scripts/format b/scripts/format new file mode 100755 index 00000000..667ec2d7 --- /dev/null +++ b/scripts/format @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +echo "==> Running formatters" +rye run format diff --git a/scripts/lint b/scripts/lint new file mode 100755 index 00000000..1d30512d --- /dev/null +++ b/scripts/lint @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if [ "$1" = "--fix" ]; then + echo "==> Running lints with --fix" + rye run fix:ruff +else + echo "==> Running lints" + rye run lint +fi + +echo "==> Making sure it imports" +rye run python -c 'import gcore' diff --git a/scripts/mock b/scripts/mock new file mode 100755 index 00000000..0b28f6ea --- /dev/null +++ b/scripts/mock @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if [[ -n "$1" && "$1" != '--'* ]]; then + URL="$1" + shift +else + URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)" +fi + +# Check if the URL is empty +if [ -z "$URL" ]; then + echo "Error: No OpenAPI spec path/url provided or found in .stats.yml" + exit 1 +fi + +echo "==> Starting mock server with URL ${URL}" + +# Run prism mock on the given spec +if [ "$1" == "--daemon" ]; then + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & + + # Wait for server to come online + echo -n "Waiting for server" + while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + echo -n "." + sleep 0.1 + done + + if grep -q "✖ fatal" ".prism.log"; then + cat .prism.log + exit 1 + fi + + echo +else + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" +fi diff --git a/scripts/test b/scripts/test new file mode 100755 index 00000000..dbeda2d2 --- /dev/null +++ b/scripts/test @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +NC='\033[0m' # No Color + +function prism_is_running() { + curl --silent "http://localhost:4010" >/dev/null 2>&1 +} + +kill_server_on_port() { + pids=$(lsof -t -i tcp:"$1" || echo "") + if [ "$pids" != "" ]; then + kill "$pids" + echo "Stopped $pids." + fi +} + +function is_overriding_api_base_url() { + [ -n "$TEST_API_BASE_URL" ] +} + +if ! is_overriding_api_base_url && ! prism_is_running ; then + # When we exit this script, make sure to kill the background mock server process + trap 'kill_server_on_port 4010' EXIT + + # Start the dev server + ./scripts/mock --daemon +fi + +if is_overriding_api_base_url ; then + echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" + echo +elif ! prism_is_running ; then + echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" + echo -e "running against your OpenAPI spec." + echo + echo -e "To run the server, pass in the path or url of your OpenAPI" + echo -e "spec to the prism command:" + echo + echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" + echo + + exit 1 +else + echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" + echo +fi + +export DEFER_PYDANTIC_BUILD=false + +echo "==> Running tests" +rye run pytest "$@" + +echo "==> Running Pydantic v1 tests" +rye run nox -s test-pydantic-v1 -- "$@" diff --git a/scripts/utils/ruffen-docs.py b/scripts/utils/ruffen-docs.py new file mode 100644 index 00000000..0cf2bd2f --- /dev/null +++ b/scripts/utils/ruffen-docs.py @@ -0,0 +1,167 @@ +# fork of https://github.com/asottile/blacken-docs adapted for ruff +from __future__ import annotations + +import re +import sys +import argparse +import textwrap +import contextlib +import subprocess +from typing import Match, Optional, Sequence, Generator, NamedTuple, cast + +MD_RE = re.compile( + r"(?P^(?P *)```\s*python\n)" r"(?P.*?)" r"(?P^(?P=indent)```\s*$)", + re.DOTALL | re.MULTILINE, +) +MD_PYCON_RE = re.compile( + r"(?P^(?P *)```\s*pycon\n)" r"(?P.*?)" r"(?P^(?P=indent)```.*$)", + re.DOTALL | re.MULTILINE, +) +PYCON_PREFIX = ">>> " +PYCON_CONTINUATION_PREFIX = "..." +PYCON_CONTINUATION_RE = re.compile( + rf"^{re.escape(PYCON_CONTINUATION_PREFIX)}( |$)", +) +DEFAULT_LINE_LENGTH = 100 + + +class CodeBlockError(NamedTuple): + offset: int + exc: Exception + + +def format_str( + src: str, +) -> tuple[str, Sequence[CodeBlockError]]: + errors: list[CodeBlockError] = [] + + @contextlib.contextmanager + def _collect_error(match: Match[str]) -> Generator[None, None, None]: + try: + yield + except Exception as e: + errors.append(CodeBlockError(match.start(), e)) + + def _md_match(match: Match[str]) -> str: + code = textwrap.dedent(match["code"]) + with _collect_error(match): + code = format_code_block(code) + code = textwrap.indent(code, match["indent"]) + return f"{match['before']}{code}{match['after']}" + + def _pycon_match(match: Match[str]) -> str: + code = "" + fragment = cast(Optional[str], None) + + def finish_fragment() -> None: + nonlocal code + nonlocal fragment + + if fragment is not None: + with _collect_error(match): + fragment = format_code_block(fragment) + fragment_lines = fragment.splitlines() + code += f"{PYCON_PREFIX}{fragment_lines[0]}\n" + for line in fragment_lines[1:]: + # Skip blank lines to handle Black adding a blank above + # functions within blocks. A blank line would end the REPL + # continuation prompt. + # + # >>> if True: + # ... def f(): + # ... pass + # ... + if line: + code += f"{PYCON_CONTINUATION_PREFIX} {line}\n" + if fragment_lines[-1].startswith(" "): + code += f"{PYCON_CONTINUATION_PREFIX}\n" + fragment = None + + indentation = None + for line in match["code"].splitlines(): + orig_line, line = line, line.lstrip() + if indentation is None and line: + indentation = len(orig_line) - len(line) + continuation_match = PYCON_CONTINUATION_RE.match(line) + if continuation_match and fragment is not None: + fragment += line[continuation_match.end() :] + "\n" + else: + finish_fragment() + if line.startswith(PYCON_PREFIX): + fragment = line[len(PYCON_PREFIX) :] + "\n" + else: + code += orig_line[indentation:] + "\n" + finish_fragment() + return code + + def _md_pycon_match(match: Match[str]) -> str: + code = _pycon_match(match) + code = textwrap.indent(code, match["indent"]) + return f"{match['before']}{code}{match['after']}" + + src = MD_RE.sub(_md_match, src) + src = MD_PYCON_RE.sub(_md_pycon_match, src) + return src, errors + + +def format_code_block(code: str) -> str: + return subprocess.check_output( + [ + sys.executable, + "-m", + "ruff", + "format", + "--stdin-filename=script.py", + f"--line-length={DEFAULT_LINE_LENGTH}", + ], + encoding="utf-8", + input=code, + ) + + +def format_file( + filename: str, + skip_errors: bool, +) -> int: + with open(filename, encoding="UTF-8") as f: + contents = f.read() + new_contents, errors = format_str(contents) + for error in errors: + lineno = contents[: error.offset].count("\n") + 1 + print(f"{filename}:{lineno}: code block parse error {error.exc}") + if errors and not skip_errors: + return 1 + if contents != new_contents: + print(f"{filename}: Rewriting...") + with open(filename, "w", encoding="UTF-8") as f: + f.write(new_contents) + return 0 + else: + return 0 + + +def main(argv: Sequence[str] | None = None) -> int: + parser = argparse.ArgumentParser() + parser.add_argument( + "-l", + "--line-length", + type=int, + default=DEFAULT_LINE_LENGTH, + ) + parser.add_argument( + "-S", + "--skip-string-normalization", + action="store_true", + ) + parser.add_argument("-E", "--skip-errors", action="store_true") + parser.add_argument("filenames", nargs="*") + args = parser.parse_args(argv) + + retv = 0 + for filename in args.filenames: + retv |= format_file(filename, skip_errors=args.skip_errors) + return retv + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh new file mode 100755 index 00000000..dcb0ac9e --- /dev/null +++ b/scripts/utils/upload-artifact.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -exuo pipefail + +FILENAME=$(basename dist/*.whl) + +RESPONSE=$(curl -X POST "$URL?filename=$FILENAME" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + +SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url') + +if [[ "$SIGNED_URL" == "null" ]]; then + echo -e "\033[31mFailed to get signed URL.\033[0m" + exit 1 +fi + +UPLOAD_RESPONSE=$(curl -v -X PUT \ + -H "Content-Type: binary/octet-stream" \ + --data-binary "@dist/$FILENAME" "$SIGNED_URL" 2>&1) + +if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then + echo -e "\033[32mUploaded build to Stainless storage.\033[0m" + echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/gcore-python/$SHA/$FILENAME'\033[0m" +else + echo -e "\033[31mFailed to upload artifact.\033[0m" + exit 1 +fi diff --git a/src/gcore/__init__.py b/src/gcore/__init__.py new file mode 100644 index 00000000..833abff8 --- /dev/null +++ b/src/gcore/__init__.py @@ -0,0 +1,92 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import typing as _t + +from . import types +from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes, omit, not_given +from ._utils import file_from_path +from ._client import Gcore, Client, Stream, Timeout, Transport, AsyncGcore, AsyncClient, AsyncStream, RequestOptions +from ._models import BaseModel +from ._version import __title__, __version__ +from ._response import APIResponse as APIResponse, AsyncAPIResponse as AsyncAPIResponse +from ._constants import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES, DEFAULT_CONNECTION_LIMITS +from ._exceptions import ( + APIError, + GcoreError, + ConflictError, + NotFoundError, + APIStatusError, + RateLimitError, + APITimeoutError, + BadRequestError, + APIConnectionError, + AuthenticationError, + InternalServerError, + PermissionDeniedError, + UnprocessableEntityError, + APIResponseValidationError, +) +from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient +from ._utils._logs import setup_logging as _setup_logging + +__all__ = [ + "types", + "__version__", + "__title__", + "NoneType", + "Transport", + "ProxiesTypes", + "NotGiven", + "NOT_GIVEN", + "not_given", + "Omit", + "omit", + "GcoreError", + "APIError", + "APIStatusError", + "APITimeoutError", + "APIConnectionError", + "APIResponseValidationError", + "BadRequestError", + "AuthenticationError", + "PermissionDeniedError", + "NotFoundError", + "ConflictError", + "UnprocessableEntityError", + "RateLimitError", + "InternalServerError", + "Timeout", + "RequestOptions", + "Client", + "AsyncClient", + "Stream", + "AsyncStream", + "Gcore", + "AsyncGcore", + "file_from_path", + "BaseModel", + "DEFAULT_TIMEOUT", + "DEFAULT_MAX_RETRIES", + "DEFAULT_CONNECTION_LIMITS", + "DefaultHttpxClient", + "DefaultAsyncHttpxClient", + "DefaultAioHttpClient", +] + +if not _t.TYPE_CHECKING: + from ._utils._resources_proxy import resources as resources + +_setup_logging() + +# Update the __module__ attribute for exported symbols so that +# error messages point to this module instead of the module +# it was originally defined in, e.g. +# gcore._exceptions.NotFoundError -> gcore.NotFoundError +__locals = locals() +for __name in __all__: + if not __name.startswith("__"): + try: + __locals[__name].__module__ = "gcore" + except (TypeError, AttributeError): + # Some of our exported symbols are builtins which we can't set attributes for. + pass diff --git a/src/gcore/_base_client.py b/src/gcore/_base_client.py new file mode 100644 index 00000000..e797b152 --- /dev/null +++ b/src/gcore/_base_client.py @@ -0,0 +1,2127 @@ +from __future__ import annotations + +import sys +import json +import time +import uuid +import email +import asyncio +import inspect +import logging +import platform +import warnings +import email.utils +from types import TracebackType +from random import random +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Type, + Union, + Generic, + Mapping, + TypeVar, + Iterable, + Iterator, + Optional, + Generator, + AsyncIterator, + cast, + overload, +) +from typing_extensions import Literal, override, get_origin + +import anyio +import httpx +import distro +import pydantic +from httpx import URL +from pydantic import PrivateAttr + +from . import _exceptions +from ._qs import Querystring +from ._files import to_httpx_files, async_to_httpx_files +from ._types import ( + Body, + Omit, + Query, + Headers, + Timeout, + NotGiven, + ResponseT, + AnyMapping, + PostParser, + BinaryTypes, + RequestFiles, + HttpxSendArgs, + RequestOptions, + AsyncBinaryTypes, + HttpxRequestFiles, + ModelBuilderProtocol, + not_given, +) +from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping +from ._compat import PYDANTIC_V1, model_copy, model_dump +from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type +from ._response import ( + APIResponse, + BaseAPIResponse, + AsyncAPIResponse, + extract_response_type, +) +from ._constants import ( + DEFAULT_TIMEOUT, + MAX_RETRY_DELAY, + DEFAULT_MAX_RETRIES, + INITIAL_RETRY_DELAY, + RAW_RESPONSE_HEADER, + OVERRIDE_CAST_TO_HEADER, + DEFAULT_CONNECTION_LIMITS, +) +from ._streaming import Stream, SSEDecoder, AsyncStream, SSEBytesDecoder +from ._exceptions import ( + APIStatusError, + APITimeoutError, + APIConnectionError, + APIResponseValidationError, +) +from ._utils._json import openapi_dumps + +log: logging.Logger = logging.getLogger(__name__) + +# TODO: make base page type vars covariant +SyncPageT = TypeVar("SyncPageT", bound="BaseSyncPage[Any]") +AsyncPageT = TypeVar("AsyncPageT", bound="BaseAsyncPage[Any]") + + +_T = TypeVar("_T") +_T_co = TypeVar("_T_co", covariant=True) + +_StreamT = TypeVar("_StreamT", bound=Stream[Any]) +_AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any]) + +if TYPE_CHECKING: + from httpx._config import ( + DEFAULT_TIMEOUT_CONFIG, # pyright: ignore[reportPrivateImportUsage] + ) + + HTTPX_DEFAULT_TIMEOUT = DEFAULT_TIMEOUT_CONFIG +else: + try: + from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT + except ImportError: + # taken from https://github.com/encode/httpx/blob/3ba5fe0d7ac70222590e759c31442b1cab263791/httpx/_config.py#L366 + HTTPX_DEFAULT_TIMEOUT = Timeout(5.0) + + +class PageInfo: + """Stores the necessary information to build the request to retrieve the next page. + + Either `url` or `params` must be set. + """ + + url: URL | NotGiven + params: Query | NotGiven + json: Body | NotGiven + + @overload + def __init__( + self, + *, + url: URL, + ) -> None: ... + + @overload + def __init__( + self, + *, + params: Query, + ) -> None: ... + + @overload + def __init__( + self, + *, + json: Body, + ) -> None: ... + + def __init__( + self, + *, + url: URL | NotGiven = not_given, + json: Body | NotGiven = not_given, + params: Query | NotGiven = not_given, + ) -> None: + self.url = url + self.json = json + self.params = params + + @override + def __repr__(self) -> str: + if self.url: + return f"{self.__class__.__name__}(url={self.url})" + if self.json: + return f"{self.__class__.__name__}(json={self.json})" + return f"{self.__class__.__name__}(params={self.params})" + + +class BasePage(GenericModel, Generic[_T]): + """ + Defines the core interface for pagination. + + Type Args: + ModelT: The pydantic model that represents an item in the response. + + Methods: + has_next_page(): Check if there is another page available + next_page_info(): Get the necessary information to make a request for the next page + """ + + _options: FinalRequestOptions = PrivateAttr() + _model: Type[_T] = PrivateAttr() + + def has_next_page(self) -> bool: + items = self._get_page_items() + if not items: + return False + return self.next_page_info() is not None + + def next_page_info(self) -> Optional[PageInfo]: ... + + def _get_page_items(self) -> Iterable[_T]: # type: ignore[empty-body] + ... + + def _params_from_url(self, url: URL) -> httpx.QueryParams: + # TODO: do we have to preprocess params here? + return httpx.QueryParams(cast(Any, self._options.params)).merge(url.params) + + def _info_to_options(self, info: PageInfo) -> FinalRequestOptions: + options = model_copy(self._options) + options._strip_raw_response_header() + + if not isinstance(info.params, NotGiven): + options.params = {**options.params, **info.params} + return options + + if not isinstance(info.url, NotGiven): + params = self._params_from_url(info.url) + url = info.url.copy_with(params=params) + options.params = dict(url.params) + options.url = str(url) + return options + + if not isinstance(info.json, NotGiven): + if not is_mapping(info.json): + raise TypeError("Pagination is only supported with mappings") + + if not options.json_data: + options.json_data = {**info.json} + else: + if not is_mapping(options.json_data): + raise TypeError("Pagination is only supported with mappings") + + options.json_data = {**options.json_data, **info.json} + return options + + raise ValueError("Unexpected PageInfo state") + + +class BaseSyncPage(BasePage[_T], Generic[_T]): + _client: SyncAPIClient = pydantic.PrivateAttr() + + def _set_private_attributes( + self, + client: SyncAPIClient, + model: Type[_T], + options: FinalRequestOptions, + ) -> None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: + self.__pydantic_private__ = {} + + self._model = model + self._client = client + self._options = options + + # Pydantic uses a custom `__iter__` method to support casting BaseModels + # to dictionaries. e.g. dict(model). + # As we want to support `for item in page`, this is inherently incompatible + # with the default pydantic behaviour. It is not possible to support both + # use cases at once. Fortunately, this is not a big deal as all other pydantic + # methods should continue to work as expected as there is an alternative method + # to cast a model to a dictionary, model.dict(), which is used internally + # by pydantic. + def __iter__(self) -> Iterator[_T]: # type: ignore + for page in self.iter_pages(): + for item in page._get_page_items(): + yield item + + def iter_pages(self: SyncPageT) -> Iterator[SyncPageT]: + page = self + while True: + yield page + if page.has_next_page(): + page = page.get_next_page() + else: + return + + def get_next_page(self: SyncPageT) -> SyncPageT: + info = self.next_page_info() + if not info: + raise RuntimeError( + "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`." + ) + + options = self._info_to_options(info) + return self._client._request_api_list(self._model, page=self.__class__, options=options) + + +class AsyncPaginator(Generic[_T, AsyncPageT]): + def __init__( + self, + client: AsyncAPIClient, + options: FinalRequestOptions, + page_cls: Type[AsyncPageT], + model: Type[_T], + ) -> None: + self._model = model + self._client = client + self._options = options + self._page_cls = page_cls + + def __await__(self) -> Generator[Any, None, AsyncPageT]: + return self._get_page().__await__() + + async def _get_page(self) -> AsyncPageT: + def _parser(resp: AsyncPageT) -> AsyncPageT: + resp._set_private_attributes( + model=self._model, + options=self._options, + client=self._client, + ) + return resp + + self._options.post_parser = _parser + + return await self._client.request(self._page_cls, self._options) + + async def __aiter__(self) -> AsyncIterator[_T]: + # https://github.com/microsoft/pyright/issues/3464 + page = cast( + AsyncPageT, + await self, # type: ignore + ) + async for item in page: + yield item + + +class BaseAsyncPage(BasePage[_T], Generic[_T]): + _client: AsyncAPIClient = pydantic.PrivateAttr() + + def _set_private_attributes( + self, + model: Type[_T], + client: AsyncAPIClient, + options: FinalRequestOptions, + ) -> None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: + self.__pydantic_private__ = {} + + self._model = model + self._client = client + self._options = options + + async def __aiter__(self) -> AsyncIterator[_T]: + async for page in self.iter_pages(): + for item in page._get_page_items(): + yield item + + async def iter_pages(self: AsyncPageT) -> AsyncIterator[AsyncPageT]: + page = self + while True: + yield page + if page.has_next_page(): + page = await page.get_next_page() + else: + return + + async def get_next_page(self: AsyncPageT) -> AsyncPageT: + info = self.next_page_info() + if not info: + raise RuntimeError( + "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`." + ) + + options = self._info_to_options(info) + return await self._client._request_api_list(self._model, page=self.__class__, options=options) + + +_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx.Client, httpx.AsyncClient]) +_DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]]) + + +class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]): + _client: _HttpxClientT + _version: str + _base_url: URL + max_retries: int + timeout: Union[float, Timeout, None] + _strict_response_validation: bool + _idempotency_header: str | None + _default_stream_cls: type[_DefaultStreamT] | None = None + + def __init__( + self, + *, + version: str, + base_url: str | URL, + _strict_response_validation: bool, + max_retries: int = DEFAULT_MAX_RETRIES, + timeout: float | Timeout | None = DEFAULT_TIMEOUT, + custom_headers: Mapping[str, str] | None = None, + custom_query: Mapping[str, object] | None = None, + ) -> None: + self._version = version + self._base_url = self._enforce_trailing_slash(URL(base_url)) + self.max_retries = max_retries + self.timeout = timeout + self._custom_headers = custom_headers or {} + self._custom_query = custom_query or {} + self._strict_response_validation = _strict_response_validation + self._idempotency_header = None + self._platform: Platform | None = None + + if max_retries is None: # pyright: ignore[reportUnnecessaryComparison] + raise TypeError( + "max_retries cannot be None. If you want to disable retries, pass `0`; if you want unlimited retries, pass `math.inf` or a very high number; if you want the default behavior, pass `gcore.DEFAULT_MAX_RETRIES`" + ) + + def _enforce_trailing_slash(self, url: URL) -> URL: + if url.raw_path.endswith(b"/"): + return url + return url.copy_with(raw_path=url.raw_path + b"/") + + def _make_status_error_from_response( + self, + response: httpx.Response, + ) -> APIStatusError: + if response.is_closed and not response.is_stream_consumed: + # We can't read the response body as it has been closed + # before it was read. This can happen if an event hook + # raises a status error. + body = None + err_msg = f"Error code: {response.status_code}" + else: + err_text = response.text.strip() + body = err_text + + try: + body = json.loads(err_text) + err_msg = f"Error code: {response.status_code} - {body}" + except Exception: + err_msg = err_text or f"Error code: {response.status_code}" + + return self._make_status_error(err_msg, body=body, response=response) + + def _make_status_error( + self, + err_msg: str, + *, + body: object, + response: httpx.Response, + ) -> _exceptions.APIStatusError: + raise NotImplementedError() + + def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0) -> httpx.Headers: + custom_headers = options.headers or {} + headers_dict = _merge_mappings(self.default_headers, custom_headers) + self._validate_headers(headers_dict, custom_headers) + + # headers are case-insensitive while dictionaries are not. + headers = httpx.Headers(headers_dict) + + idempotency_header = self._idempotency_header + if idempotency_header and options.idempotency_key and idempotency_header not in headers: + headers[idempotency_header] = options.idempotency_key + + # Don't set these headers if they were already set or removed by the caller. We check + # `custom_headers`, which can contain `Omit()`, instead of `headers` to account for the removal case. + lower_custom_headers = [header.lower() for header in custom_headers] + if "x-stainless-retry-count" not in lower_custom_headers: + headers["x-stainless-retry-count"] = str(retries_taken) + if "x-stainless-read-timeout" not in lower_custom_headers: + timeout = self.timeout if isinstance(options.timeout, NotGiven) else options.timeout + if isinstance(timeout, Timeout): + timeout = timeout.read + if timeout is not None: + headers["x-stainless-read-timeout"] = str(timeout) + + return headers + + def _prepare_url(self, url: str) -> URL: + """ + Merge a URL argument together with any 'base_url' on the client, + to create the URL used for the outgoing request. + """ + # Copied from httpx's `_merge_url` method. + merge_url = URL(url) + if merge_url.is_relative_url: + merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/") + return self.base_url.copy_with(raw_path=merge_raw_path) + + return merge_url + + def _make_sse_decoder(self) -> SSEDecoder | SSEBytesDecoder: + return SSEDecoder() + + def _build_request( + self, + options: FinalRequestOptions, + *, + retries_taken: int = 0, + ) -> httpx.Request: + if log.isEnabledFor(logging.DEBUG): + log.debug( + "Request options: %s", + model_dump( + options, + exclude_unset=True, + # Pydantic v1 can't dump every type we support in content, so we exclude it for now. + exclude={ + "content", + } + if PYDANTIC_V1 + else {}, + ), + ) + kwargs: dict[str, Any] = {} + + json_data = options.json_data + if options.extra_json is not None: + if json_data is None: + json_data = cast(Body, options.extra_json) + elif is_mapping(json_data): + json_data = _merge_mappings(json_data, options.extra_json) + else: + raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`") + + headers = self._build_headers(options, retries_taken=retries_taken) + params = _merge_mappings(self.default_query, options.params) + content_type = headers.get("Content-Type") + files = options.files + + # If the given Content-Type header is multipart/form-data then it + # has to be removed so that httpx can generate the header with + # additional information for us as it has to be in this form + # for the server to be able to correctly parse the request: + # multipart/form-data; boundary=---abc-- + if content_type is not None and content_type.startswith("multipart/form-data"): + if "boundary" not in content_type: + # only remove the header if the boundary hasn't been explicitly set + # as the caller doesn't want httpx to come up with their own boundary + headers.pop("Content-Type") + + # As we are now sending multipart/form-data instead of application/json + # we need to tell httpx to use it, https://www.python-httpx.org/advanced/clients/#multipart-file-encoding + if json_data: + if not is_dict(json_data): + raise TypeError( + f"Expected query input to be a dictionary for multipart requests but got {type(json_data)} instead." + ) + kwargs["data"] = self._serialize_multipartform(json_data) + + # httpx determines whether or not to send a "multipart/form-data" + # request based on the truthiness of the "files" argument. + # This gets around that issue by generating a dict value that + # evaluates to true. + # + # https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186 + if not files: + files = cast(HttpxRequestFiles, ForceMultipartDict()) + + prepared_url = self._prepare_url(options.url) + if "_" in prepared_url.host: + # work around https://github.com/encode/httpx/discussions/2880 + kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} + + is_body_allowed = options.method.lower() != "get" + + if is_body_allowed: + if options.content is not None and json_data is not None: + raise TypeError("Passing both `content` and `json_data` is not supported") + if options.content is not None and files is not None: + raise TypeError("Passing both `content` and `files` is not supported") + if options.content is not None: + kwargs["content"] = options.content + elif isinstance(json_data, bytes): + kwargs["content"] = json_data + elif not files: + # Don't set content when JSON is sent as multipart/form-data, + # since httpx's content param overrides other body arguments + kwargs["content"] = openapi_dumps(json_data) if is_given(json_data) and json_data is not None else None + kwargs["files"] = files + else: + headers.pop("Content-Type", None) + kwargs.pop("data", None) + + # TODO: report this error to httpx + return self._client.build_request( # pyright: ignore[reportUnknownMemberType] + headers=headers, + timeout=self.timeout if isinstance(options.timeout, NotGiven) else options.timeout, + method=options.method, + url=prepared_url, + # the `Query` type that we use is incompatible with qs' + # `Params` type as it needs to be typed as `Mapping[str, object]` + # so that passing a `TypedDict` doesn't cause an error. + # https://github.com/microsoft/pyright/issues/3526#event-6715453066 + params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None, + **kwargs, + ) + + def _serialize_multipartform(self, data: Mapping[object, object]) -> dict[str, object]: + items = self.qs.stringify_items( + # TODO: type ignore is required as stringify_items is well typed but we can't be + # well typed without heavy validation. + data, # type: ignore + array_format="brackets", + ) + serialized: dict[str, object] = {} + for key, value in items: + existing = serialized.get(key) + + if not existing: + serialized[key] = value + continue + + # If a value has already been set for this key then that + # means we're sending data like `array[]=[1, 2, 3]` and we + # need to tell httpx that we want to send multiple values with + # the same key which is done by using a list or a tuple. + # + # Note: 2d arrays should never result in the same key at both + # levels so it's safe to assume that if the value is a list, + # it was because we changed it to be a list. + if is_list(existing): + existing.append(value) + else: + serialized[key] = [existing, value] + + return serialized + + def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalRequestOptions) -> type[ResponseT]: + if not is_given(options.headers): + return cast_to + + # make a copy of the headers so we don't mutate user-input + headers = dict(options.headers) + + # we internally support defining a temporary header to override the + # default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response` + # see _response.py for implementation details + override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, not_given) + if is_given(override_cast_to): + options.headers = headers + return cast(Type[ResponseT], override_cast_to) + + return cast_to + + def _should_stream_response_body(self, request: httpx.Request) -> bool: + return request.headers.get(RAW_RESPONSE_HEADER) == "stream" # type: ignore[no-any-return] + + def _process_response_data( + self, + *, + data: object, + cast_to: type[ResponseT], + response: httpx.Response, + ) -> ResponseT: + if data is None: + return cast(ResponseT, None) + + if cast_to is object: + return cast(ResponseT, data) + + try: + if inspect.isclass(cast_to) and issubclass(cast_to, ModelBuilderProtocol): + return cast(ResponseT, cast_to.build(response=response, data=data)) + + if self._strict_response_validation: + return cast(ResponseT, validate_type(type_=cast_to, value=data)) + + return cast(ResponseT, construct_type(type_=cast_to, value=data)) + except pydantic.ValidationError as err: + raise APIResponseValidationError(response=response, body=data) from err + + @property + def qs(self) -> Querystring: + return Querystring() + + @property + def custom_auth(self) -> httpx.Auth | None: + return None + + @property + def auth_headers(self) -> dict[str, str]: + return {} + + @property + def default_headers(self) -> dict[str, str | Omit]: + return { + "Accept": "application/json", + "Content-Type": "application/json", + "User-Agent": self.user_agent, + **self.platform_headers(), + **self.auth_headers, + **self._custom_headers, + } + + @property + def default_query(self) -> dict[str, object]: + return { + **self._custom_query, + } + + def _validate_headers( + self, + headers: Headers, # noqa: ARG002 + custom_headers: Headers, # noqa: ARG002 + ) -> None: + """Validate the given default headers and custom headers. + + Does nothing by default. + """ + return + + @property + def user_agent(self) -> str: + return f"{self.__class__.__name__}/Python {self._version}" + + @property + def base_url(self) -> URL: + return self._base_url + + @base_url.setter + def base_url(self, url: URL | str) -> None: + self._base_url = self._enforce_trailing_slash(url if isinstance(url, URL) else URL(url)) + + def platform_headers(self) -> Dict[str, str]: + # the actual implementation is in a separate `lru_cache` decorated + # function because adding `lru_cache` to methods will leak memory + # https://github.com/python/cpython/issues/88476 + return platform_headers(self._version, platform=self._platform) + + def _parse_retry_after_header(self, response_headers: Optional[httpx.Headers] = None) -> float | None: + """Returns a float of the number of seconds (not milliseconds) to wait after retrying, or None if unspecified. + + About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After + See also https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After#syntax + """ + if response_headers is None: + return None + + # First, try the non-standard `retry-after-ms` header for milliseconds, + # which is more precise than integer-seconds `retry-after` + try: + retry_ms_header = response_headers.get("retry-after-ms", None) + return float(retry_ms_header) / 1000 + except (TypeError, ValueError): + pass + + # Next, try parsing `retry-after` header as seconds (allowing nonstandard floats). + retry_header = response_headers.get("retry-after") + try: + # note: the spec indicates that this should only ever be an integer + # but if someone sends a float there's no reason for us to not respect it + return float(retry_header) + except (TypeError, ValueError): + pass + + # Last, try parsing `retry-after` as a date. + retry_date_tuple = email.utils.parsedate_tz(retry_header) + if retry_date_tuple is None: + return None + + retry_date = email.utils.mktime_tz(retry_date_tuple) + return float(retry_date - time.time()) + + def _calculate_retry_timeout( + self, + remaining_retries: int, + options: FinalRequestOptions, + response_headers: Optional[httpx.Headers] = None, + ) -> float: + max_retries = options.get_max_retries(self.max_retries) + + # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says. + retry_after = self._parse_retry_after_header(response_headers) + if retry_after is not None and 0 < retry_after <= 60: + return retry_after + + # Also cap retry count to 1000 to avoid any potential overflows with `pow` + nb_retries = min(max_retries - remaining_retries, 1000) + + # Apply exponential backoff, but not more than the max. + sleep_seconds = min(INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY) + + # Apply some jitter, plus-or-minus half a second. + jitter = 1 - 0.25 * random() + timeout = sleep_seconds * jitter + return timeout if timeout >= 0 else 0 + + def _should_retry(self, response: httpx.Response) -> bool: + # Note: this is not a standard header + should_retry_header = response.headers.get("x-should-retry") + + # If the server explicitly says whether or not to retry, obey. + if should_retry_header == "true": + log.debug("Retrying as header `x-should-retry` is set to `true`") + return True + if should_retry_header == "false": + log.debug("Not retrying as header `x-should-retry` is set to `false`") + return False + + # Retry on request timeouts. + if response.status_code == 408: + log.debug("Retrying due to status code %i", response.status_code) + return True + + # Retry on lock timeouts. + if response.status_code == 409: + log.debug("Retrying due to status code %i", response.status_code) + return True + + # Retry on rate limits. + if response.status_code == 429: + log.debug("Retrying due to status code %i", response.status_code) + return True + + # Retry internal errors. + if response.status_code >= 500: + log.debug("Retrying due to status code %i", response.status_code) + return True + + log.debug("Not retrying") + return False + + def _idempotency_key(self) -> str: + return f"stainless-python-retry-{uuid.uuid4()}" + + +class _DefaultHttpxClient(httpx.Client): + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + super().__init__(**kwargs) + + +if TYPE_CHECKING: + DefaultHttpxClient = httpx.Client + """An alias to `httpx.Client` that provides the same defaults that this SDK + uses internally. + + This is useful because overriding the `http_client` with your own instance of + `httpx.Client` will result in httpx's defaults being used, not ours. + """ +else: + DefaultHttpxClient = _DefaultHttpxClient + + +class SyncHttpxClientWrapper(DefaultHttpxClient): + def __del__(self) -> None: + if self.is_closed: + return + + try: + self.close() + except Exception: + pass + + +class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]): + _client: httpx.Client + _default_stream_cls: type[Stream[Any]] | None = None + + def __init__( + self, + *, + version: str, + base_url: str | URL, + max_retries: int = DEFAULT_MAX_RETRIES, + timeout: float | Timeout | None | NotGiven = not_given, + http_client: httpx.Client | None = None, + custom_headers: Mapping[str, str] | None = None, + custom_query: Mapping[str, object] | None = None, + _strict_response_validation: bool, + ) -> None: + if not is_given(timeout): + # if the user passed in a custom http client with a non-default + # timeout set then we use that timeout. + # + # note: there is an edge case here where the user passes in a client + # where they've explicitly set the timeout to match the default timeout + # as this check is structural, meaning that we'll think they didn't + # pass in a timeout and will ignore it + if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT: + timeout = http_client.timeout + else: + timeout = DEFAULT_TIMEOUT + + if http_client is not None and not isinstance(http_client, httpx.Client): # pyright: ignore[reportUnnecessaryIsInstance] + raise TypeError( + f"Invalid `http_client` argument; Expected an instance of `httpx.Client` but got {type(http_client)}" + ) + + super().__init__( + version=version, + # cast to a valid type because mypy doesn't understand our type narrowing + timeout=cast(Timeout, timeout), + base_url=base_url, + max_retries=max_retries, + custom_query=custom_query, + custom_headers=custom_headers, + _strict_response_validation=_strict_response_validation, + ) + self._client = http_client or SyncHttpxClientWrapper( + base_url=base_url, + # cast to a valid type because mypy doesn't understand our type narrowing + timeout=cast(Timeout, timeout), + ) + + def is_closed(self) -> bool: + return self._client.is_closed + + def close(self) -> None: + """Close the underlying HTTPX client. + + The client will *not* be usable after this. + """ + # If an error is thrown while constructing a client, self._client + # may not be present + if hasattr(self, "_client"): + self._client.close() + + def __enter__(self: _T) -> _T: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.close() + + def _prepare_options( + self, + options: FinalRequestOptions, # noqa: ARG002 + ) -> FinalRequestOptions: + """Hook for mutating the given options""" + return options + + def _prepare_request( + self, + request: httpx.Request, # noqa: ARG002 + ) -> None: + """This method is used as a callback for mutating the `Request` object + after it has been constructed. + This is useful for cases where you want to add certain headers based off of + the request properties, e.g. `url`, `method` etc. + """ + return None + + @overload + def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: Literal[True], + stream_cls: Type[_StreamT], + ) -> _StreamT: ... + + @overload + def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: bool = False, + stream_cls: Type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: ... + + def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: bool = False, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: + cast_to = self._maybe_override_cast_to(cast_to, options) + + # create a copy of the options we were given so that if the + # options are mutated later & we then retry, the retries are + # given the original options + input_options = model_copy(options) + if input_options.idempotency_key is None and input_options.method.lower() != "get": + # ensure the idempotency key is reused between requests + input_options.idempotency_key = self._idempotency_key() + + response: httpx.Response | None = None + max_retries = input_options.get_max_retries(self.max_retries) + + retries_taken = 0 + for retries_taken in range(max_retries + 1): + options = model_copy(input_options) + options = self._prepare_options(options) + + remaining_retries = max_retries - retries_taken + request = self._build_request(options, retries_taken=retries_taken) + self._prepare_request(request) + + kwargs: HttpxSendArgs = {} + if self.custom_auth is not None: + kwargs["auth"] = self.custom_auth + + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + + log.debug("Sending HTTP Request: %s %s", request.method, request.url) + + response = None + try: + response = self._client.send( + request, + stream=stream or self._should_stream_response_body(request=request), + **kwargs, + ) + except httpx.TimeoutException as err: + log.debug("Encountered httpx.TimeoutException", exc_info=True) + + if remaining_retries > 0: + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising timeout error") + raise APITimeoutError(request=request) from err + except Exception as err: + log.debug("Encountered Exception", exc_info=True) + + if remaining_retries > 0: + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising connection error") + raise APIConnectionError(request=request) from err + + log.debug( + 'HTTP Response: %s %s "%i %s" %s', + request.method, + request.url, + response.status_code, + response.reason_phrase, + response.headers, + ) + + try: + response.raise_for_status() + except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code + log.debug("Encountered httpx.HTTPStatusError", exc_info=True) + + if remaining_retries > 0 and self._should_retry(err.response): + err.response.close() + self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=response, + ) + continue + + # If the response is streamed then we need to explicitly read the response + # to completion before attempting to access the response text. + if not err.response.is_closed: + err.response.read() + + log.debug("Re-raising status error") + raise self._make_status_error_from_response(err.response) from None + + break + + assert response is not None, "could not resolve response (should never happen)" + return self._process_response( + cast_to=cast_to, + options=options, + response=response, + stream=stream, + stream_cls=stream_cls, + retries_taken=retries_taken, + ) + + def _sleep_for_retry( + self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None + ) -> None: + remaining_retries = max_retries - retries_taken + if remaining_retries == 1: + log.debug("1 retry left") + else: + log.debug("%i retries left", remaining_retries) + + timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) + log.info("Retrying request to %s in %f seconds", options.url, timeout) + + time.sleep(timeout) + + def _process_response( + self, + *, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + response: httpx.Response, + stream: bool, + stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + retries_taken: int = 0, + ) -> ResponseT: + origin = get_origin(cast_to) or cast_to + + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): + if not issubclass(origin, APIResponse): + raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}") + + response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) + return cast( + ResponseT, + response_cls( + raw=response, + client=self, + cast_to=extract_response_type(response_cls), + stream=stream, + stream_cls=stream_cls, + options=options, + retries_taken=retries_taken, + ), + ) + + if cast_to == httpx.Response: + return cast(ResponseT, response) + + api_response = APIResponse( + raw=response, + client=self, + cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] + stream=stream, + stream_cls=stream_cls, + options=options, + retries_taken=retries_taken, + ) + if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): + return cast(ResponseT, api_response) + + return api_response.parse() + + def _request_api_list( + self, + model: Type[object], + page: Type[SyncPageT], + options: FinalRequestOptions, + ) -> SyncPageT: + def _parser(resp: SyncPageT) -> SyncPageT: + resp._set_private_attributes( + client=self, + model=model, + options=options, + ) + return resp + + options.post_parser = _parser + + return self.request(page, options, stream=False) + + @overload + def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: Literal[True], + stream_cls: type[_StreamT], + ) -> _StreamT: ... + + @overload + def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: bool, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: ... + + def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: bool = False, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: + opts = FinalRequestOptions.construct(method="get", url=path, **options) + # cast is required because mypy complains about returning Any even though + # it understands the type variables + return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) + + @overload + def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + options: RequestOptions = {}, + files: RequestFiles | None = None, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + options: RequestOptions = {}, + files: RequestFiles | None = None, + stream: Literal[True], + stream_cls: type[_StreamT], + ) -> _StreamT: ... + + @overload + def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + options: RequestOptions = {}, + files: RequestFiles | None = None, + stream: bool, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: ... + + def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + options: RequestOptions = {}, + files: RequestFiles | None = None, + stream: bool = False, + stream_cls: type[_StreamT] | None = None, + ) -> ResponseT | _StreamT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="post", url=path, json_data=body, content=content, files=to_httpx_files(files), **options + ) + return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) + + def patch( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="patch", url=path, json_data=body, content=content, files=to_httpx_files(files), **options + ) + return self.request(cast_to, opts) + + def put( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="put", url=path, json_data=body, content=content, files=to_httpx_files(files), **options + ) + return self.request(cast_to, opts) + + def delete( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: BinaryTypes | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) + return self.request(cast_to, opts) + + def get_api_list( + self, + path: str, + *, + model: Type[object], + page: Type[SyncPageT], + body: Body | None = None, + options: RequestOptions = {}, + method: str = "get", + ) -> SyncPageT: + opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options) + return self._request_api_list(model, page, opts) + + +class _DefaultAsyncHttpxClient(httpx.AsyncClient): + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + super().__init__(**kwargs) + + +try: + import httpx_aiohttp +except ImportError: + + class _DefaultAioHttpClient(httpx.AsyncClient): + def __init__(self, **_kwargs: Any) -> None: + raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra") +else: + + class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + + super().__init__(**kwargs) + + +if TYPE_CHECKING: + DefaultAsyncHttpxClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK + uses internally. + + This is useful because overriding the `http_client` with your own instance of + `httpx.AsyncClient` will result in httpx's defaults being used, not ours. + """ + + DefaultAioHttpClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`.""" +else: + DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient + DefaultAioHttpClient = _DefaultAioHttpClient + + +class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): + def __del__(self) -> None: + if self.is_closed: + return + + try: + # TODO(someday): support non asyncio runtimes here + asyncio.get_running_loop().create_task(self.aclose()) + except Exception: + pass + + +class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]): + _client: httpx.AsyncClient + _default_stream_cls: type[AsyncStream[Any]] | None = None + + def __init__( + self, + *, + version: str, + base_url: str | URL, + _strict_response_validation: bool, + max_retries: int = DEFAULT_MAX_RETRIES, + timeout: float | Timeout | None | NotGiven = not_given, + http_client: httpx.AsyncClient | None = None, + custom_headers: Mapping[str, str] | None = None, + custom_query: Mapping[str, object] | None = None, + ) -> None: + if not is_given(timeout): + # if the user passed in a custom http client with a non-default + # timeout set then we use that timeout. + # + # note: there is an edge case here where the user passes in a client + # where they've explicitly set the timeout to match the default timeout + # as this check is structural, meaning that we'll think they didn't + # pass in a timeout and will ignore it + if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT: + timeout = http_client.timeout + else: + timeout = DEFAULT_TIMEOUT + + if http_client is not None and not isinstance(http_client, httpx.AsyncClient): # pyright: ignore[reportUnnecessaryIsInstance] + raise TypeError( + f"Invalid `http_client` argument; Expected an instance of `httpx.AsyncClient` but got {type(http_client)}" + ) + + super().__init__( + version=version, + base_url=base_url, + # cast to a valid type because mypy doesn't understand our type narrowing + timeout=cast(Timeout, timeout), + max_retries=max_retries, + custom_query=custom_query, + custom_headers=custom_headers, + _strict_response_validation=_strict_response_validation, + ) + self._client = http_client or AsyncHttpxClientWrapper( + base_url=base_url, + # cast to a valid type because mypy doesn't understand our type narrowing + timeout=cast(Timeout, timeout), + ) + + def is_closed(self) -> bool: + return self._client.is_closed + + async def close(self) -> None: + """Close the underlying HTTPX client. + + The client will *not* be usable after this. + """ + await self._client.aclose() + + async def __aenter__(self: _T) -> _T: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + await self.close() + + async def _prepare_options( + self, + options: FinalRequestOptions, # noqa: ARG002 + ) -> FinalRequestOptions: + """Hook for mutating the given options""" + return options + + async def _prepare_request( + self, + request: httpx.Request, # noqa: ARG002 + ) -> None: + """This method is used as a callback for mutating the `Request` object + after it has been constructed. + This is useful for cases where you want to add certain headers based off of + the request properties, e.g. `url`, `method` etc. + """ + return None + + @overload + async def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + async def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: Literal[True], + stream_cls: type[_AsyncStreamT], + ) -> _AsyncStreamT: ... + + @overload + async def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: bool, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: ... + + async def request( + self, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + *, + stream: bool = False, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: + if self._platform is None: + # `get_platform` can make blocking IO calls so we + # execute it earlier while we are in an async context + self._platform = await asyncify(get_platform)() + + cast_to = self._maybe_override_cast_to(cast_to, options) + + # create a copy of the options we were given so that if the + # options are mutated later & we then retry, the retries are + # given the original options + input_options = model_copy(options) + if input_options.idempotency_key is None and input_options.method.lower() != "get": + # ensure the idempotency key is reused between requests + input_options.idempotency_key = self._idempotency_key() + + response: httpx.Response | None = None + max_retries = input_options.get_max_retries(self.max_retries) + + retries_taken = 0 + for retries_taken in range(max_retries + 1): + options = model_copy(input_options) + options = await self._prepare_options(options) + + remaining_retries = max_retries - retries_taken + request = self._build_request(options, retries_taken=retries_taken) + await self._prepare_request(request) + + kwargs: HttpxSendArgs = {} + if self.custom_auth is not None: + kwargs["auth"] = self.custom_auth + + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + + log.debug("Sending HTTP Request: %s %s", request.method, request.url) + + response = None + try: + response = await self._client.send( + request, + stream=stream or self._should_stream_response_body(request=request), + **kwargs, + ) + except httpx.TimeoutException as err: + log.debug("Encountered httpx.TimeoutException", exc_info=True) + + if remaining_retries > 0: + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising timeout error") + raise APITimeoutError(request=request) from err + except Exception as err: + log.debug("Encountered Exception", exc_info=True) + + if remaining_retries > 0: + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=None, + ) + continue + + log.debug("Raising connection error") + raise APIConnectionError(request=request) from err + + log.debug( + 'HTTP Response: %s %s "%i %s" %s', + request.method, + request.url, + response.status_code, + response.reason_phrase, + response.headers, + ) + + try: + response.raise_for_status() + except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code + log.debug("Encountered httpx.HTTPStatusError", exc_info=True) + + if remaining_retries > 0 and self._should_retry(err.response): + await err.response.aclose() + await self._sleep_for_retry( + retries_taken=retries_taken, + max_retries=max_retries, + options=input_options, + response=response, + ) + continue + + # If the response is streamed then we need to explicitly read the response + # to completion before attempting to access the response text. + if not err.response.is_closed: + await err.response.aread() + + log.debug("Re-raising status error") + raise self._make_status_error_from_response(err.response) from None + + break + + assert response is not None, "could not resolve response (should never happen)" + return await self._process_response( + cast_to=cast_to, + options=options, + response=response, + stream=stream, + stream_cls=stream_cls, + retries_taken=retries_taken, + ) + + async def _sleep_for_retry( + self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None + ) -> None: + remaining_retries = max_retries - retries_taken + if remaining_retries == 1: + log.debug("1 retry left") + else: + log.debug("%i retries left", remaining_retries) + + timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) + log.info("Retrying request to %s in %f seconds", options.url, timeout) + + await anyio.sleep(timeout) + + async def _process_response( + self, + *, + cast_to: Type[ResponseT], + options: FinalRequestOptions, + response: httpx.Response, + stream: bool, + stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + retries_taken: int = 0, + ) -> ResponseT: + origin = get_origin(cast_to) or cast_to + + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): + if not issubclass(origin, AsyncAPIResponse): + raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}") + + response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) + return cast( + "ResponseT", + response_cls( + raw=response, + client=self, + cast_to=extract_response_type(response_cls), + stream=stream, + stream_cls=stream_cls, + options=options, + retries_taken=retries_taken, + ), + ) + + if cast_to == httpx.Response: + return cast(ResponseT, response) + + api_response = AsyncAPIResponse( + raw=response, + client=self, + cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] + stream=stream, + stream_cls=stream_cls, + options=options, + retries_taken=retries_taken, + ) + if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): + return cast(ResponseT, api_response) + + return await api_response.parse() + + def _request_api_list( + self, + model: Type[_T], + page: Type[AsyncPageT], + options: FinalRequestOptions, + ) -> AsyncPaginator[_T, AsyncPageT]: + return AsyncPaginator(client=self, options=options, page_cls=page, model=model) + + @overload + async def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + async def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: Literal[True], + stream_cls: type[_AsyncStreamT], + ) -> _AsyncStreamT: ... + + @overload + async def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: bool, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: ... + + async def get( + self, + path: str, + *, + cast_to: Type[ResponseT], + options: RequestOptions = {}, + stream: bool = False, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: + opts = FinalRequestOptions.construct(method="get", url=path, **options) + return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) + + @overload + async def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + stream: Literal[False] = False, + ) -> ResponseT: ... + + @overload + async def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + stream: Literal[True], + stream_cls: type[_AsyncStreamT], + ) -> _AsyncStreamT: ... + + @overload + async def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + stream: bool, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: ... + + async def post( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + stream: bool = False, + stream_cls: type[_AsyncStreamT] | None = None, + ) -> ResponseT | _AsyncStreamT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="post", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options + ) + return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) + + async def patch( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="patch", + url=path, + json_data=body, + content=content, + files=await async_to_httpx_files(files), + **options, + ) + return await self.request(cast_to, opts) + + async def put( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="put", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options + ) + return await self.request(cast_to, opts) + + async def delete( + self, + path: str, + *, + cast_to: Type[ResponseT], + body: Body | None = None, + content: AsyncBinaryTypes | None = None, + options: RequestOptions = {}, + ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) + return await self.request(cast_to, opts) + + def get_api_list( + self, + path: str, + *, + model: Type[_T], + page: Type[AsyncPageT], + body: Body | None = None, + options: RequestOptions = {}, + method: str = "get", + ) -> AsyncPaginator[_T, AsyncPageT]: + opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options) + return self._request_api_list(model, page, opts) + + +def make_request_options( + *, + query: Query | None = None, + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + idempotency_key: str | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + post_parser: PostParser | NotGiven = not_given, +) -> RequestOptions: + """Create a dict of type RequestOptions without keys of NotGiven values.""" + options: RequestOptions = {} + if extra_headers is not None: + options["headers"] = extra_headers + + if extra_body is not None: + options["extra_json"] = cast(AnyMapping, extra_body) + + if query is not None: + options["params"] = query + + if extra_query is not None: + options["params"] = {**options.get("params", {}), **extra_query} + + if not isinstance(timeout, NotGiven): + options["timeout"] = timeout + + if idempotency_key is not None: + options["idempotency_key"] = idempotency_key + + if is_given(post_parser): + # internal + options["post_parser"] = post_parser # type: ignore + + return options + + +class ForceMultipartDict(Dict[str, None]): + def __bool__(self) -> bool: + return True + + +class OtherPlatform: + def __init__(self, name: str) -> None: + self.name = name + + @override + def __str__(self) -> str: + return f"Other:{self.name}" + + +Platform = Union[ + OtherPlatform, + Literal[ + "MacOS", + "Linux", + "Windows", + "FreeBSD", + "OpenBSD", + "iOS", + "Android", + "Unknown", + ], +] + + +def get_platform() -> Platform: + try: + system = platform.system().lower() + platform_name = platform.platform().lower() + except Exception: + return "Unknown" + + if "iphone" in platform_name or "ipad" in platform_name: + # Tested using Python3IDE on an iPhone 11 and Pythonista on an iPad 7 + # system is Darwin and platform_name is a string like: + # - Darwin-21.6.0-iPhone12,1-64bit + # - Darwin-21.6.0-iPad7,11-64bit + return "iOS" + + if system == "darwin": + return "MacOS" + + if system == "windows": + return "Windows" + + if "android" in platform_name: + # Tested using Pydroid 3 + # system is Linux and platform_name is a string like 'Linux-5.10.81-android12-9-00001-geba40aecb3b7-ab8534902-aarch64-with-libc' + return "Android" + + if system == "linux": + # https://distro.readthedocs.io/en/latest/#distro.id + distro_id = distro.id() + if distro_id == "freebsd": + return "FreeBSD" + + if distro_id == "openbsd": + return "OpenBSD" + + return "Linux" + + if platform_name: + return OtherPlatform(platform_name) + + return "Unknown" + + +@lru_cache(maxsize=None) +def platform_headers(version: str, *, platform: Platform | None) -> Dict[str, str]: + return { + "X-Stainless-Lang": "python", + "X-Stainless-Package-Version": version, + "X-Stainless-OS": str(platform or get_platform()), + "X-Stainless-Arch": str(get_architecture()), + "X-Stainless-Runtime": get_python_runtime(), + "X-Stainless-Runtime-Version": get_python_version(), + } + + +class OtherArch: + def __init__(self, name: str) -> None: + self.name = name + + @override + def __str__(self) -> str: + return f"other:{self.name}" + + +Arch = Union[OtherArch, Literal["x32", "x64", "arm", "arm64", "unknown"]] + + +def get_python_runtime() -> str: + try: + return platform.python_implementation() + except Exception: + return "unknown" + + +def get_python_version() -> str: + try: + return platform.python_version() + except Exception: + return "unknown" + + +def get_architecture() -> Arch: + try: + machine = platform.machine().lower() + except Exception: + return "unknown" + + if machine in ("arm64", "aarch64"): + return "arm64" + + # TODO: untested + if machine == "arm": + return "arm" + + if machine == "x86_64": + return "x64" + + # TODO: untested + if sys.maxsize <= 2**32: + return "x32" + + if machine: + return OtherArch(machine) + + return "unknown" + + +def _merge_mappings( + obj1: Mapping[_T_co, Union[_T, Omit]], + obj2: Mapping[_T_co, Union[_T, Omit]], +) -> Dict[_T_co, _T]: + """Merge two mappings of the same type, removing any values that are instances of `Omit`. + + In cases with duplicate keys the second mapping takes precedence. + """ + merged = {**obj1, **obj2} + return {key: value for key, value in merged.items() if not isinstance(value, Omit)} diff --git a/src/gcore/_client.py b/src/gcore/_client.py new file mode 100644 index 00000000..d43fa1cb --- /dev/null +++ b/src/gcore/_client.py @@ -0,0 +1,844 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import TYPE_CHECKING, Any, Mapping +from typing_extensions import Self, override + +import httpx + +from . import _exceptions +from ._qs import Querystring +from ._types import ( + Omit, + Timeout, + NotGiven, + Transport, + ProxiesTypes, + RequestOptions, + not_given, +) +from ._utils import is_given, get_async_library, maybe_coerce_integer +from ._compat import cached_property +from ._version import __version__ +from ._streaming import Stream as Stream, AsyncStream as AsyncStream +from ._exceptions import GcoreError, APIStatusError +from ._base_client import ( + DEFAULT_MAX_RETRIES, + SyncAPIClient, + AsyncAPIClient, +) + +if TYPE_CHECKING: + from .resources import cdn, dns, iam, waap, cloud, storage, fastedge, security, streaming + from .resources.cdn.cdn import CDNResource, AsyncCDNResource + from .resources.dns.dns import DNSResource, AsyncDNSResource + from .resources.iam.iam import IamResource, AsyncIamResource + from .resources.waap.waap import WaapResource, AsyncWaapResource + from .resources.cloud.cloud import CloudResource, AsyncCloudResource + from .resources.storage.storage import StorageResource, AsyncStorageResource + from .resources.fastedge.fastedge import FastedgeResource, AsyncFastedgeResource + from .resources.security.security import SecurityResource, AsyncSecurityResource + from .resources.streaming.streaming import StreamingResource, AsyncStreamingResource + +__all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Gcore", "AsyncGcore", "Client", "AsyncClient"] + + +class Gcore(SyncAPIClient): + # client options + api_key: str + cloud_project_id: int | None + cloud_region_id: int | None + cloud_polling_interval_seconds: int | None + cloud_polling_timeout_seconds: int | None + + def __init__( + self, + *, + api_key: str | None = None, + cloud_project_id: int | None = None, + cloud_region_id: int | None = None, + cloud_polling_interval_seconds: int | None = 3, + cloud_polling_timeout_seconds: int | None = 7200, + base_url: str | httpx.URL | None = None, + timeout: float | Timeout | None | NotGiven = not_given, + max_retries: int = DEFAULT_MAX_RETRIES, + default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + # Configure a custom httpx client. + # We provide a `DefaultHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`. + # See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details. + http_client: httpx.Client | None = None, + # Enable or disable schema validation for data returned by the API. + # When enabled an error APIResponseValidationError is raised + # if the API responds with invalid data for the expected schema. + # + # This parameter may be removed or changed in the future. + # If you rely on this feature, please open a GitHub issue + # outlining your use-case to help us decide if it should be + # part of our public interface in the future. + _strict_response_validation: bool = False, + ) -> None: + """Construct a new synchronous Gcore client instance. + + This automatically infers the following arguments from their corresponding environment variables if they are not provided: + - `api_key` from `GCORE_API_KEY` + - `cloud_project_id` from `GCORE_CLOUD_PROJECT_ID` + - `cloud_region_id` from `GCORE_CLOUD_REGION_ID` + """ + if api_key is None: + api_key = os.environ.get("GCORE_API_KEY") + if api_key is None: + raise GcoreError( + "The api_key client option must be set either by passing api_key to the client or by setting the GCORE_API_KEY environment variable" + ) + self.api_key = api_key + + if cloud_project_id is None: + cloud_project_id = maybe_coerce_integer(os.environ.get("GCORE_CLOUD_PROJECT_ID")) + self.cloud_project_id = cloud_project_id + + if cloud_region_id is None: + cloud_region_id = maybe_coerce_integer(os.environ.get("GCORE_CLOUD_REGION_ID")) + self.cloud_region_id = cloud_region_id + + if cloud_polling_interval_seconds is None: + cloud_polling_interval_seconds = 3 + self.cloud_polling_interval_seconds = cloud_polling_interval_seconds + + if cloud_polling_timeout_seconds is None: + cloud_polling_timeout_seconds = 7200 + self.cloud_polling_timeout_seconds = cloud_polling_timeout_seconds + + if base_url is None: + base_url = os.environ.get("GCORE_BASE_URL") + if base_url is None: + base_url = f"https://api.gcore.com" + + super().__init__( + version=__version__, + base_url=base_url, + max_retries=max_retries, + timeout=timeout, + http_client=http_client, + custom_headers=default_headers, + custom_query=default_query, + _strict_response_validation=_strict_response_validation, + ) + + @cached_property + def cloud(self) -> CloudResource: + from .resources.cloud import CloudResource + + return CloudResource(self) + + @cached_property + def waap(self) -> WaapResource: + from .resources.waap import WaapResource + + return WaapResource(self) + + @cached_property + def iam(self) -> IamResource: + from .resources.iam import IamResource + + return IamResource(self) + + @cached_property + def fastedge(self) -> FastedgeResource: + from .resources.fastedge import FastedgeResource + + return FastedgeResource(self) + + @cached_property + def streaming(self) -> StreamingResource: + from .resources.streaming import StreamingResource + + return StreamingResource(self) + + @cached_property + def security(self) -> SecurityResource: + from .resources.security import SecurityResource + + return SecurityResource(self) + + @cached_property + def dns(self) -> DNSResource: + from .resources.dns import DNSResource + + return DNSResource(self) + + @cached_property + def storage(self) -> StorageResource: + from .resources.storage import StorageResource + + return StorageResource(self) + + @cached_property + def cdn(self) -> CDNResource: + from .resources.cdn import CDNResource + + return CDNResource(self) + + @cached_property + def with_raw_response(self) -> GcoreWithRawResponse: + return GcoreWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> GcoreWithStreamedResponse: + return GcoreWithStreamedResponse(self) + + @property + @override + def qs(self) -> Querystring: + return Querystring(nested_format="dots", array_format="repeat") + + @property + @override + def auth_headers(self) -> dict[str, str]: + api_key = self.api_key + return {"Authorization": f"APIKey {api_key}"} + + @property + @override + def default_headers(self) -> dict[str, str | Omit]: + return { + **super().default_headers, + "X-Stainless-Async": "false", + **self._custom_headers, + } + + def copy( + self, + *, + api_key: str | None = None, + cloud_project_id: int | None = None, + cloud_region_id: int | None = None, + cloud_polling_interval_seconds: int | None = None, + cloud_polling_timeout_seconds: int | None = None, + base_url: str | httpx.URL | None = None, + timeout: float | Timeout | None | NotGiven = not_given, + http_client: httpx.Client | None = None, + max_retries: int | NotGiven = not_given, + default_headers: Mapping[str, str] | None = None, + set_default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + set_default_query: Mapping[str, object] | None = None, + _extra_kwargs: Mapping[str, Any] = {}, + ) -> Self: + """ + Create a new client instance re-using the same options given to the current client with optional overriding. + """ + if default_headers is not None and set_default_headers is not None: + raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") + + if default_query is not None and set_default_query is not None: + raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") + + headers = self._custom_headers + if default_headers is not None: + headers = {**headers, **default_headers} + elif set_default_headers is not None: + headers = set_default_headers + + params = self._custom_query + if default_query is not None: + params = {**params, **default_query} + elif set_default_query is not None: + params = set_default_query + + http_client = http_client or self._client + return self.__class__( + api_key=api_key or self.api_key, + cloud_project_id=cloud_project_id or self.cloud_project_id, + cloud_region_id=cloud_region_id or self.cloud_region_id, + cloud_polling_interval_seconds=cloud_polling_interval_seconds or self.cloud_polling_interval_seconds, + cloud_polling_timeout_seconds=cloud_polling_timeout_seconds or self.cloud_polling_timeout_seconds, + base_url=base_url or self.base_url, + timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, + http_client=http_client, + max_retries=max_retries if is_given(max_retries) else self.max_retries, + default_headers=headers, + default_query=params, + **_extra_kwargs, + ) + + # Alias for `copy` for nicer inline usage, e.g. + # client.with_options(timeout=10).foo.create(...) + with_options = copy + + def _get_cloud_project_id_path_param(self) -> int: + from_client = self.cloud_project_id + if from_client is not None: + return from_client + + raise ValueError( + "Missing cloud_project_id argument; Please provide it at the client level, e.g. Gcore(cloud_project_id='abcd') or per method." + ) + + def _get_cloud_region_id_path_param(self) -> int: + from_client = self.cloud_region_id + if from_client is not None: + return from_client + + raise ValueError( + "Missing cloud_region_id argument; Please provide it at the client level, e.g. Gcore(cloud_region_id='abcd') or per method." + ) + + @override + def _make_status_error( + self, + err_msg: str, + *, + body: object, + response: httpx.Response, + ) -> APIStatusError: + if response.status_code == 400: + return _exceptions.BadRequestError(err_msg, response=response, body=body) + + if response.status_code == 401: + return _exceptions.AuthenticationError(err_msg, response=response, body=body) + + if response.status_code == 403: + return _exceptions.PermissionDeniedError(err_msg, response=response, body=body) + + if response.status_code == 404: + return _exceptions.NotFoundError(err_msg, response=response, body=body) + + if response.status_code == 409: + return _exceptions.ConflictError(err_msg, response=response, body=body) + + if response.status_code == 422: + return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body) + + if response.status_code == 429: + return _exceptions.RateLimitError(err_msg, response=response, body=body) + + if response.status_code >= 500: + return _exceptions.InternalServerError(err_msg, response=response, body=body) + return APIStatusError(err_msg, response=response, body=body) + + +class AsyncGcore(AsyncAPIClient): + # client options + api_key: str + cloud_project_id: int | None + cloud_region_id: int | None + cloud_polling_interval_seconds: int | None + cloud_polling_timeout_seconds: int | None + + def __init__( + self, + *, + api_key: str | None = None, + cloud_project_id: int | None = None, + cloud_region_id: int | None = None, + cloud_polling_interval_seconds: int | None = 3, + cloud_polling_timeout_seconds: int | None = 7200, + base_url: str | httpx.URL | None = None, + timeout: float | Timeout | None | NotGiven = not_given, + max_retries: int = DEFAULT_MAX_RETRIES, + default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + # Configure a custom httpx client. + # We provide a `DefaultAsyncHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`. + # See the [httpx documentation](https://www.python-httpx.org/api/#asyncclient) for more details. + http_client: httpx.AsyncClient | None = None, + # Enable or disable schema validation for data returned by the API. + # When enabled an error APIResponseValidationError is raised + # if the API responds with invalid data for the expected schema. + # + # This parameter may be removed or changed in the future. + # If you rely on this feature, please open a GitHub issue + # outlining your use-case to help us decide if it should be + # part of our public interface in the future. + _strict_response_validation: bool = False, + ) -> None: + """Construct a new async AsyncGcore client instance. + + This automatically infers the following arguments from their corresponding environment variables if they are not provided: + - `api_key` from `GCORE_API_KEY` + - `cloud_project_id` from `GCORE_CLOUD_PROJECT_ID` + - `cloud_region_id` from `GCORE_CLOUD_REGION_ID` + """ + if api_key is None: + api_key = os.environ.get("GCORE_API_KEY") + if api_key is None: + raise GcoreError( + "The api_key client option must be set either by passing api_key to the client or by setting the GCORE_API_KEY environment variable" + ) + self.api_key = api_key + + if cloud_project_id is None: + cloud_project_id = maybe_coerce_integer(os.environ.get("GCORE_CLOUD_PROJECT_ID")) + self.cloud_project_id = cloud_project_id + + if cloud_region_id is None: + cloud_region_id = maybe_coerce_integer(os.environ.get("GCORE_CLOUD_REGION_ID")) + self.cloud_region_id = cloud_region_id + + if cloud_polling_interval_seconds is None: + cloud_polling_interval_seconds = 3 + self.cloud_polling_interval_seconds = cloud_polling_interval_seconds + + if cloud_polling_timeout_seconds is None: + cloud_polling_timeout_seconds = 7200 + self.cloud_polling_timeout_seconds = cloud_polling_timeout_seconds + + if base_url is None: + base_url = os.environ.get("GCORE_BASE_URL") + if base_url is None: + base_url = f"https://api.gcore.com" + + super().__init__( + version=__version__, + base_url=base_url, + max_retries=max_retries, + timeout=timeout, + http_client=http_client, + custom_headers=default_headers, + custom_query=default_query, + _strict_response_validation=_strict_response_validation, + ) + + @cached_property + def cloud(self) -> AsyncCloudResource: + from .resources.cloud import AsyncCloudResource + + return AsyncCloudResource(self) + + @cached_property + def waap(self) -> AsyncWaapResource: + from .resources.waap import AsyncWaapResource + + return AsyncWaapResource(self) + + @cached_property + def iam(self) -> AsyncIamResource: + from .resources.iam import AsyncIamResource + + return AsyncIamResource(self) + + @cached_property + def fastedge(self) -> AsyncFastedgeResource: + from .resources.fastedge import AsyncFastedgeResource + + return AsyncFastedgeResource(self) + + @cached_property + def streaming(self) -> AsyncStreamingResource: + from .resources.streaming import AsyncStreamingResource + + return AsyncStreamingResource(self) + + @cached_property + def security(self) -> AsyncSecurityResource: + from .resources.security import AsyncSecurityResource + + return AsyncSecurityResource(self) + + @cached_property + def dns(self) -> AsyncDNSResource: + from .resources.dns import AsyncDNSResource + + return AsyncDNSResource(self) + + @cached_property + def storage(self) -> AsyncStorageResource: + from .resources.storage import AsyncStorageResource + + return AsyncStorageResource(self) + + @cached_property + def cdn(self) -> AsyncCDNResource: + from .resources.cdn import AsyncCDNResource + + return AsyncCDNResource(self) + + @cached_property + def with_raw_response(self) -> AsyncGcoreWithRawResponse: + return AsyncGcoreWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncGcoreWithStreamedResponse: + return AsyncGcoreWithStreamedResponse(self) + + @property + @override + def qs(self) -> Querystring: + return Querystring(nested_format="dots", array_format="repeat") + + @property + @override + def auth_headers(self) -> dict[str, str]: + api_key = self.api_key + return {"Authorization": f"APIKey {api_key}"} + + @property + @override + def default_headers(self) -> dict[str, str | Omit]: + return { + **super().default_headers, + "X-Stainless-Async": f"async:{get_async_library()}", + **self._custom_headers, + } + + def copy( + self, + *, + api_key: str | None = None, + cloud_project_id: int | None = None, + cloud_region_id: int | None = None, + cloud_polling_interval_seconds: int | None = None, + cloud_polling_timeout_seconds: int | None = None, + base_url: str | httpx.URL | None = None, + timeout: float | Timeout | None | NotGiven = not_given, + http_client: httpx.AsyncClient | None = None, + max_retries: int | NotGiven = not_given, + default_headers: Mapping[str, str] | None = None, + set_default_headers: Mapping[str, str] | None = None, + default_query: Mapping[str, object] | None = None, + set_default_query: Mapping[str, object] | None = None, + _extra_kwargs: Mapping[str, Any] = {}, + ) -> Self: + """ + Create a new client instance re-using the same options given to the current client with optional overriding. + """ + if default_headers is not None and set_default_headers is not None: + raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") + + if default_query is not None and set_default_query is not None: + raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") + + headers = self._custom_headers + if default_headers is not None: + headers = {**headers, **default_headers} + elif set_default_headers is not None: + headers = set_default_headers + + params = self._custom_query + if default_query is not None: + params = {**params, **default_query} + elif set_default_query is not None: + params = set_default_query + + http_client = http_client or self._client + return self.__class__( + api_key=api_key or self.api_key, + cloud_project_id=cloud_project_id or self.cloud_project_id, + cloud_region_id=cloud_region_id or self.cloud_region_id, + cloud_polling_interval_seconds=cloud_polling_interval_seconds or self.cloud_polling_interval_seconds, + cloud_polling_timeout_seconds=cloud_polling_timeout_seconds or self.cloud_polling_timeout_seconds, + base_url=base_url or self.base_url, + timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, + http_client=http_client, + max_retries=max_retries if is_given(max_retries) else self.max_retries, + default_headers=headers, + default_query=params, + **_extra_kwargs, + ) + + # Alias for `copy` for nicer inline usage, e.g. + # client.with_options(timeout=10).foo.create(...) + with_options = copy + + def _get_cloud_project_id_path_param(self) -> int: + from_client = self.cloud_project_id + if from_client is not None: + return from_client + + raise ValueError( + "Missing cloud_project_id argument; Please provide it at the client level, e.g. AsyncGcore(cloud_project_id='abcd') or per method." + ) + + def _get_cloud_region_id_path_param(self) -> int: + from_client = self.cloud_region_id + if from_client is not None: + return from_client + + raise ValueError( + "Missing cloud_region_id argument; Please provide it at the client level, e.g. AsyncGcore(cloud_region_id='abcd') or per method." + ) + + @override + def _make_status_error( + self, + err_msg: str, + *, + body: object, + response: httpx.Response, + ) -> APIStatusError: + if response.status_code == 400: + return _exceptions.BadRequestError(err_msg, response=response, body=body) + + if response.status_code == 401: + return _exceptions.AuthenticationError(err_msg, response=response, body=body) + + if response.status_code == 403: + return _exceptions.PermissionDeniedError(err_msg, response=response, body=body) + + if response.status_code == 404: + return _exceptions.NotFoundError(err_msg, response=response, body=body) + + if response.status_code == 409: + return _exceptions.ConflictError(err_msg, response=response, body=body) + + if response.status_code == 422: + return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body) + + if response.status_code == 429: + return _exceptions.RateLimitError(err_msg, response=response, body=body) + + if response.status_code >= 500: + return _exceptions.InternalServerError(err_msg, response=response, body=body) + return APIStatusError(err_msg, response=response, body=body) + + +class GcoreWithRawResponse: + _client: Gcore + + def __init__(self, client: Gcore) -> None: + self._client = client + + @cached_property + def cloud(self) -> cloud.CloudResourceWithRawResponse: + from .resources.cloud import CloudResourceWithRawResponse + + return CloudResourceWithRawResponse(self._client.cloud) + + @cached_property + def waap(self) -> waap.WaapResourceWithRawResponse: + from .resources.waap import WaapResourceWithRawResponse + + return WaapResourceWithRawResponse(self._client.waap) + + @cached_property + def iam(self) -> iam.IamResourceWithRawResponse: + from .resources.iam import IamResourceWithRawResponse + + return IamResourceWithRawResponse(self._client.iam) + + @cached_property + def fastedge(self) -> fastedge.FastedgeResourceWithRawResponse: + from .resources.fastedge import FastedgeResourceWithRawResponse + + return FastedgeResourceWithRawResponse(self._client.fastedge) + + @cached_property + def streaming(self) -> streaming.StreamingResourceWithRawResponse: + from .resources.streaming import StreamingResourceWithRawResponse + + return StreamingResourceWithRawResponse(self._client.streaming) + + @cached_property + def security(self) -> security.SecurityResourceWithRawResponse: + from .resources.security import SecurityResourceWithRawResponse + + return SecurityResourceWithRawResponse(self._client.security) + + @cached_property + def dns(self) -> dns.DNSResourceWithRawResponse: + from .resources.dns import DNSResourceWithRawResponse + + return DNSResourceWithRawResponse(self._client.dns) + + @cached_property + def storage(self) -> storage.StorageResourceWithRawResponse: + from .resources.storage import StorageResourceWithRawResponse + + return StorageResourceWithRawResponse(self._client.storage) + + @cached_property + def cdn(self) -> cdn.CDNResourceWithRawResponse: + from .resources.cdn import CDNResourceWithRawResponse + + return CDNResourceWithRawResponse(self._client.cdn) + + +class AsyncGcoreWithRawResponse: + _client: AsyncGcore + + def __init__(self, client: AsyncGcore) -> None: + self._client = client + + @cached_property + def cloud(self) -> cloud.AsyncCloudResourceWithRawResponse: + from .resources.cloud import AsyncCloudResourceWithRawResponse + + return AsyncCloudResourceWithRawResponse(self._client.cloud) + + @cached_property + def waap(self) -> waap.AsyncWaapResourceWithRawResponse: + from .resources.waap import AsyncWaapResourceWithRawResponse + + return AsyncWaapResourceWithRawResponse(self._client.waap) + + @cached_property + def iam(self) -> iam.AsyncIamResourceWithRawResponse: + from .resources.iam import AsyncIamResourceWithRawResponse + + return AsyncIamResourceWithRawResponse(self._client.iam) + + @cached_property + def fastedge(self) -> fastedge.AsyncFastedgeResourceWithRawResponse: + from .resources.fastedge import AsyncFastedgeResourceWithRawResponse + + return AsyncFastedgeResourceWithRawResponse(self._client.fastedge) + + @cached_property + def streaming(self) -> streaming.AsyncStreamingResourceWithRawResponse: + from .resources.streaming import AsyncStreamingResourceWithRawResponse + + return AsyncStreamingResourceWithRawResponse(self._client.streaming) + + @cached_property + def security(self) -> security.AsyncSecurityResourceWithRawResponse: + from .resources.security import AsyncSecurityResourceWithRawResponse + + return AsyncSecurityResourceWithRawResponse(self._client.security) + + @cached_property + def dns(self) -> dns.AsyncDNSResourceWithRawResponse: + from .resources.dns import AsyncDNSResourceWithRawResponse + + return AsyncDNSResourceWithRawResponse(self._client.dns) + + @cached_property + def storage(self) -> storage.AsyncStorageResourceWithRawResponse: + from .resources.storage import AsyncStorageResourceWithRawResponse + + return AsyncStorageResourceWithRawResponse(self._client.storage) + + @cached_property + def cdn(self) -> cdn.AsyncCDNResourceWithRawResponse: + from .resources.cdn import AsyncCDNResourceWithRawResponse + + return AsyncCDNResourceWithRawResponse(self._client.cdn) + + +class GcoreWithStreamedResponse: + _client: Gcore + + def __init__(self, client: Gcore) -> None: + self._client = client + + @cached_property + def cloud(self) -> cloud.CloudResourceWithStreamingResponse: + from .resources.cloud import CloudResourceWithStreamingResponse + + return CloudResourceWithStreamingResponse(self._client.cloud) + + @cached_property + def waap(self) -> waap.WaapResourceWithStreamingResponse: + from .resources.waap import WaapResourceWithStreamingResponse + + return WaapResourceWithStreamingResponse(self._client.waap) + + @cached_property + def iam(self) -> iam.IamResourceWithStreamingResponse: + from .resources.iam import IamResourceWithStreamingResponse + + return IamResourceWithStreamingResponse(self._client.iam) + + @cached_property + def fastedge(self) -> fastedge.FastedgeResourceWithStreamingResponse: + from .resources.fastedge import FastedgeResourceWithStreamingResponse + + return FastedgeResourceWithStreamingResponse(self._client.fastedge) + + @cached_property + def streaming(self) -> streaming.StreamingResourceWithStreamingResponse: + from .resources.streaming import StreamingResourceWithStreamingResponse + + return StreamingResourceWithStreamingResponse(self._client.streaming) + + @cached_property + def security(self) -> security.SecurityResourceWithStreamingResponse: + from .resources.security import SecurityResourceWithStreamingResponse + + return SecurityResourceWithStreamingResponse(self._client.security) + + @cached_property + def dns(self) -> dns.DNSResourceWithStreamingResponse: + from .resources.dns import DNSResourceWithStreamingResponse + + return DNSResourceWithStreamingResponse(self._client.dns) + + @cached_property + def storage(self) -> storage.StorageResourceWithStreamingResponse: + from .resources.storage import StorageResourceWithStreamingResponse + + return StorageResourceWithStreamingResponse(self._client.storage) + + @cached_property + def cdn(self) -> cdn.CDNResourceWithStreamingResponse: + from .resources.cdn import CDNResourceWithStreamingResponse + + return CDNResourceWithStreamingResponse(self._client.cdn) + + +class AsyncGcoreWithStreamedResponse: + _client: AsyncGcore + + def __init__(self, client: AsyncGcore) -> None: + self._client = client + + @cached_property + def cloud(self) -> cloud.AsyncCloudResourceWithStreamingResponse: + from .resources.cloud import AsyncCloudResourceWithStreamingResponse + + return AsyncCloudResourceWithStreamingResponse(self._client.cloud) + + @cached_property + def waap(self) -> waap.AsyncWaapResourceWithStreamingResponse: + from .resources.waap import AsyncWaapResourceWithStreamingResponse + + return AsyncWaapResourceWithStreamingResponse(self._client.waap) + + @cached_property + def iam(self) -> iam.AsyncIamResourceWithStreamingResponse: + from .resources.iam import AsyncIamResourceWithStreamingResponse + + return AsyncIamResourceWithStreamingResponse(self._client.iam) + + @cached_property + def fastedge(self) -> fastedge.AsyncFastedgeResourceWithStreamingResponse: + from .resources.fastedge import AsyncFastedgeResourceWithStreamingResponse + + return AsyncFastedgeResourceWithStreamingResponse(self._client.fastedge) + + @cached_property + def streaming(self) -> streaming.AsyncStreamingResourceWithStreamingResponse: + from .resources.streaming import AsyncStreamingResourceWithStreamingResponse + + return AsyncStreamingResourceWithStreamingResponse(self._client.streaming) + + @cached_property + def security(self) -> security.AsyncSecurityResourceWithStreamingResponse: + from .resources.security import AsyncSecurityResourceWithStreamingResponse + + return AsyncSecurityResourceWithStreamingResponse(self._client.security) + + @cached_property + def dns(self) -> dns.AsyncDNSResourceWithStreamingResponse: + from .resources.dns import AsyncDNSResourceWithStreamingResponse + + return AsyncDNSResourceWithStreamingResponse(self._client.dns) + + @cached_property + def storage(self) -> storage.AsyncStorageResourceWithStreamingResponse: + from .resources.storage import AsyncStorageResourceWithStreamingResponse + + return AsyncStorageResourceWithStreamingResponse(self._client.storage) + + @cached_property + def cdn(self) -> cdn.AsyncCDNResourceWithStreamingResponse: + from .resources.cdn import AsyncCDNResourceWithStreamingResponse + + return AsyncCDNResourceWithStreamingResponse(self._client.cdn) + + +Client = Gcore + +AsyncClient = AsyncGcore diff --git a/src/gcore/_compat.py b/src/gcore/_compat.py new file mode 100644 index 00000000..786ff42a --- /dev/null +++ b/src/gcore/_compat.py @@ -0,0 +1,219 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload +from datetime import date, datetime +from typing_extensions import Self, Literal + +import pydantic +from pydantic.fields import FieldInfo + +from ._types import IncEx, StrBytesIntFloat + +_T = TypeVar("_T") +_ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel) + +# --------------- Pydantic v2, v3 compatibility --------------- + +# Pyright incorrectly reports some of our functions as overriding a method when they don't +# pyright: reportIncompatibleMethodOverride=false + +PYDANTIC_V1 = pydantic.VERSION.startswith("1.") + +if TYPE_CHECKING: + + def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 + ... + + def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: # noqa: ARG001 + ... + + def get_args(t: type[Any]) -> tuple[Any, ...]: # noqa: ARG001 + ... + + def is_union(tp: type[Any] | None) -> bool: # noqa: ARG001 + ... + + def get_origin(t: type[Any]) -> type[Any] | None: # noqa: ARG001 + ... + + def is_literal_type(type_: type[Any]) -> bool: # noqa: ARG001 + ... + + def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 + ... + +else: + # v1 re-exports + if PYDANTIC_V1: + from pydantic.typing import ( + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + is_typeddict as is_typeddict, + is_literal_type as is_literal_type, + ) + from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime + else: + from ._utils import ( + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + parse_date as parse_date, + is_typeddict as is_typeddict, + parse_datetime as parse_datetime, + is_literal_type as is_literal_type, + ) + + +# refactored config +if TYPE_CHECKING: + from pydantic import ConfigDict as ConfigDict +else: + if PYDANTIC_V1: + # TODO: provide an error message here? + ConfigDict = None + else: + from pydantic import ConfigDict as ConfigDict + + +# renamed methods / properties +def parse_obj(model: type[_ModelT], value: object) -> _ModelT: + if PYDANTIC_V1: + return cast(_ModelT, model.parse_obj(value)) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + else: + return model.model_validate(value) + + +def field_is_required(field: FieldInfo) -> bool: + if PYDANTIC_V1: + return field.required # type: ignore + return field.is_required() + + +def field_get_default(field: FieldInfo) -> Any: + value = field.get_default() + if PYDANTIC_V1: + return value + from pydantic_core import PydanticUndefined + + if value == PydanticUndefined: + return None + return value + + +def field_outer_type(field: FieldInfo) -> Any: + if PYDANTIC_V1: + return field.outer_type_ # type: ignore + return field.annotation + + +def get_model_config(model: type[pydantic.BaseModel]) -> Any: + if PYDANTIC_V1: + return model.__config__ # type: ignore + return model.model_config + + +def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]: + if PYDANTIC_V1: + return model.__fields__ # type: ignore + return model.model_fields + + +def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT: + if PYDANTIC_V1: + return model.copy(deep=deep) # type: ignore + return model.model_copy(deep=deep) + + +def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: + if PYDANTIC_V1: + return model.json(indent=indent) # type: ignore + return model.model_dump_json(indent=indent) + + +def model_dump( + model: pydantic.BaseModel, + *, + exclude: IncEx | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + warnings: bool = True, + mode: Literal["json", "python"] = "python", + by_alias: bool | None = None, +) -> dict[str, Any]: + if (not PYDANTIC_V1) or hasattr(model, "model_dump"): + return model.model_dump( + mode=mode, + exclude=exclude, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + # warnings are not supported in Pydantic v1 + warnings=True if PYDANTIC_V1 else warnings, + by_alias=by_alias, + ) + return cast( + "dict[str, Any]", + model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias) + ), + ) + + +def model_parse(model: type[_ModelT], data: Any) -> _ModelT: + if PYDANTIC_V1: + return model.parse_obj(data) # pyright: ignore[reportDeprecated] + return model.model_validate(data) + + +# generic models +if TYPE_CHECKING: + + class GenericModel(pydantic.BaseModel): ... + +else: + if PYDANTIC_V1: + import pydantic.generics + + class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... + else: + # there no longer needs to be a distinction in v2 but + # we still have to create our own subclass to avoid + # inconsistent MRO ordering errors + class GenericModel(pydantic.BaseModel): ... + + +# cached properties +if TYPE_CHECKING: + cached_property = property + + # we define a separate type (copied from typeshed) + # that represents that `cached_property` is `set`able + # at runtime, which differs from `@property`. + # + # this is a separate type as editors likely special case + # `@property` and we don't want to cause issues just to have + # more helpful internal types. + + class typed_cached_property(Generic[_T]): + func: Callable[[Any], _T] + attrname: str | None + + def __init__(self, func: Callable[[Any], _T]) -> None: ... + + @overload + def __get__(self, instance: None, owner: type[Any] | None = None) -> Self: ... + + @overload + def __get__(self, instance: object, owner: type[Any] | None = None) -> _T: ... + + def __get__(self, instance: object, owner: type[Any] | None = None) -> _T | Self: + raise NotImplementedError() + + def __set_name__(self, owner: type[Any], name: str) -> None: ... + + # __set__ is not defined at runtime, but @cached_property is designed to be settable + def __set__(self, instance: object, value: _T) -> None: ... +else: + from functools import cached_property as cached_property + + typed_cached_property = cached_property diff --git a/src/gcore/_constants.py b/src/gcore/_constants.py new file mode 100644 index 00000000..3d06978d --- /dev/null +++ b/src/gcore/_constants.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import httpx + +RAW_RESPONSE_HEADER = "X-Stainless-Raw-Response" +OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to" + +# default timeout is 2 minutes +DEFAULT_TIMEOUT = httpx.Timeout(timeout=120, connect=5.0) +DEFAULT_MAX_RETRIES = 2 +DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20) + +INITIAL_RETRY_DELAY = 0.5 +MAX_RETRY_DELAY = 8.0 diff --git a/src/gcore/_exceptions.py b/src/gcore/_exceptions.py new file mode 100644 index 00000000..ed737b61 --- /dev/null +++ b/src/gcore/_exceptions.py @@ -0,0 +1,108 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +__all__ = [ + "BadRequestError", + "AuthenticationError", + "PermissionDeniedError", + "NotFoundError", + "ConflictError", + "UnprocessableEntityError", + "RateLimitError", + "InternalServerError", +] + + +class GcoreError(Exception): + pass + + +class APIError(GcoreError): + message: str + request: httpx.Request + + body: object | None + """The API response body. + + If the API responded with a valid JSON structure then this property will be the + decoded result. + + If it isn't a valid JSON structure then this will be the raw response. + + If there was no response associated with this error then it will be `None`. + """ + + def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None: # noqa: ARG002 + super().__init__(message) + self.request = request + self.message = message + self.body = body + + +class APIResponseValidationError(APIError): + response: httpx.Response + status_code: int + + def __init__(self, response: httpx.Response, body: object | None, *, message: str | None = None) -> None: + super().__init__(message or "Data returned by API invalid for expected schema.", response.request, body=body) + self.response = response + self.status_code = response.status_code + + +class APIStatusError(APIError): + """Raised when an API response has a status code of 4xx or 5xx.""" + + response: httpx.Response + status_code: int + + def __init__(self, message: str, *, response: httpx.Response, body: object | None) -> None: + super().__init__(message, response.request, body=body) + self.response = response + self.status_code = response.status_code + + +class APIConnectionError(APIError): + def __init__(self, *, message: str = "Connection error.", request: httpx.Request) -> None: + super().__init__(message, request, body=None) + + +class APITimeoutError(APIConnectionError): + def __init__(self, request: httpx.Request) -> None: + super().__init__(message="Request timed out.", request=request) + + +class BadRequestError(APIStatusError): + status_code: Literal[400] = 400 # pyright: ignore[reportIncompatibleVariableOverride] + + +class AuthenticationError(APIStatusError): + status_code: Literal[401] = 401 # pyright: ignore[reportIncompatibleVariableOverride] + + +class PermissionDeniedError(APIStatusError): + status_code: Literal[403] = 403 # pyright: ignore[reportIncompatibleVariableOverride] + + +class NotFoundError(APIStatusError): + status_code: Literal[404] = 404 # pyright: ignore[reportIncompatibleVariableOverride] + + +class ConflictError(APIStatusError): + status_code: Literal[409] = 409 # pyright: ignore[reportIncompatibleVariableOverride] + + +class UnprocessableEntityError(APIStatusError): + status_code: Literal[422] = 422 # pyright: ignore[reportIncompatibleVariableOverride] + + +class RateLimitError(APIStatusError): + status_code: Literal[429] = 429 # pyright: ignore[reportIncompatibleVariableOverride] + + +class InternalServerError(APIStatusError): + pass diff --git a/src/gcore/_files.py b/src/gcore/_files.py new file mode 100644 index 00000000..cc14c14f --- /dev/null +++ b/src/gcore/_files.py @@ -0,0 +1,123 @@ +from __future__ import annotations + +import io +import os +import pathlib +from typing import overload +from typing_extensions import TypeGuard + +import anyio + +from ._types import ( + FileTypes, + FileContent, + RequestFiles, + HttpxFileTypes, + Base64FileInput, + HttpxFileContent, + HttpxRequestFiles, +) +from ._utils import is_tuple_t, is_mapping_t, is_sequence_t + + +def is_base64_file_input(obj: object) -> TypeGuard[Base64FileInput]: + return isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) + + +def is_file_content(obj: object) -> TypeGuard[FileContent]: + return ( + isinstance(obj, bytes) or isinstance(obj, tuple) or isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) + ) + + +def assert_is_file_content(obj: object, *, key: str | None = None) -> None: + if not is_file_content(obj): + prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`" + raise RuntimeError( + f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead." + ) from None + + +@overload +def to_httpx_files(files: None) -> None: ... + + +@overload +def to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... + + +def to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: + if files is None: + return None + + if is_mapping_t(files): + files = {key: _transform_file(file) for key, file in files.items()} + elif is_sequence_t(files): + files = [(key, _transform_file(file)) for key, file in files] + else: + raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence") + + return files + + +def _transform_file(file: FileTypes) -> HttpxFileTypes: + if is_file_content(file): + if isinstance(file, os.PathLike): + path = pathlib.Path(file) + return (path.name, path.read_bytes()) + + return file + + if is_tuple_t(file): + return (file[0], read_file_content(file[1]), *file[2:]) + + raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") + + +def read_file_content(file: FileContent) -> HttpxFileContent: + if isinstance(file, os.PathLike): + return pathlib.Path(file).read_bytes() + return file + + +@overload +async def async_to_httpx_files(files: None) -> None: ... + + +@overload +async def async_to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... + + +async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: + if files is None: + return None + + if is_mapping_t(files): + files = {key: await _async_transform_file(file) for key, file in files.items()} + elif is_sequence_t(files): + files = [(key, await _async_transform_file(file)) for key, file in files] + else: + raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence") + + return files + + +async def _async_transform_file(file: FileTypes) -> HttpxFileTypes: + if is_file_content(file): + if isinstance(file, os.PathLike): + path = anyio.Path(file) + return (path.name, await path.read_bytes()) + + return file + + if is_tuple_t(file): + return (file[0], await async_read_file_content(file[1]), *file[2:]) + + raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") + + +async def async_read_file_content(file: FileContent) -> HttpxFileContent: + if isinstance(file, os.PathLike): + return await anyio.Path(file).read_bytes() + + return file diff --git a/src/gcore/_models.py b/src/gcore/_models.py new file mode 100644 index 00000000..29070e05 --- /dev/null +++ b/src/gcore/_models.py @@ -0,0 +1,872 @@ +from __future__ import annotations + +import os +import inspect +import weakref +from typing import ( + IO, + TYPE_CHECKING, + Any, + Type, + Union, + Generic, + TypeVar, + Callable, + Iterable, + Optional, + AsyncIterable, + cast, +) +from datetime import date, datetime +from typing_extensions import ( + List, + Unpack, + Literal, + ClassVar, + Protocol, + Required, + ParamSpec, + TypedDict, + TypeGuard, + final, + override, + runtime_checkable, +) + +import pydantic +from pydantic.fields import FieldInfo + +from ._types import ( + Body, + IncEx, + Query, + ModelT, + Headers, + Timeout, + NotGiven, + AnyMapping, + HttpxRequestFiles, +) +from ._utils import ( + PropertyInfo, + is_list, + is_given, + json_safe, + lru_cache, + is_mapping, + parse_date, + coerce_boolean, + parse_datetime, + strip_not_given, + extract_type_arg, + is_annotated_type, + is_type_alias_type, + strip_annotated_type, +) +from ._compat import ( + PYDANTIC_V1, + ConfigDict, + GenericModel as BaseGenericModel, + get_args, + is_union, + parse_obj, + get_origin, + is_literal_type, + get_model_config, + get_model_fields, + field_get_default, +) +from ._constants import RAW_RESPONSE_HEADER + +if TYPE_CHECKING: + from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema + +__all__ = ["BaseModel", "GenericModel"] + +_T = TypeVar("_T") +_BaseModelT = TypeVar("_BaseModelT", bound="BaseModel") + +P = ParamSpec("P") + + +@runtime_checkable +class _ConfigProtocol(Protocol): + allow_population_by_field_name: bool + + +class BaseModel(pydantic.BaseModel): + if PYDANTIC_V1: + + @property + @override + def model_fields_set(self) -> set[str]: + # a forwards-compat shim for pydantic v2 + return self.__fields_set__ # type: ignore + + class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] + extra: Any = pydantic.Extra.allow # type: ignore + else: + model_config: ClassVar[ConfigDict] = ConfigDict( + extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) + ) + + def to_dict( + self, + *, + mode: Literal["json", "python"] = "python", + use_api_names: bool = True, + exclude_unset: bool = True, + exclude_defaults: bool = False, + exclude_none: bool = False, + warnings: bool = True, + ) -> dict[str, object]: + """Recursively generate a dictionary representation of the model, optionally specifying which fields to include or exclude. + + By default, fields that were not set by the API will not be included, + and keys will match the API response, *not* the property names from the model. + + For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, + the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). + + Args: + mode: + If mode is 'json', the dictionary will only contain JSON serializable types. e.g. `datetime` will be turned into a string, `"2024-3-22T18:11:19.117000Z"`. + If mode is 'python', the dictionary may contain any Python objects. e.g. `datetime(2024, 3, 22)` + + use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value from the output. + exclude_none: Whether to exclude fields that have a value of `None` from the output. + warnings: Whether to log warnings when invalid fields are encountered. This is only supported in Pydantic v2. + """ + return self.model_dump( + mode=mode, + by_alias=use_api_names, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + warnings=warnings, + ) + + def to_json( + self, + *, + indent: int | None = 2, + use_api_names: bool = True, + exclude_unset: bool = True, + exclude_defaults: bool = False, + exclude_none: bool = False, + warnings: bool = True, + ) -> str: + """Generates a JSON string representing this model as it would be received from or sent to the API (but with indentation). + + By default, fields that were not set by the API will not be included, + and keys will match the API response, *not* the property names from the model. + + For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, + the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). + + Args: + indent: Indentation to use in the JSON output. If `None` is passed, the output will be compact. Defaults to `2` + use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that have the default value. + exclude_none: Whether to exclude fields that have a value of `None`. + warnings: Whether to show any warnings that occurred during serialization. This is only supported in Pydantic v2. + """ + return self.model_dump_json( + indent=indent, + by_alias=use_api_names, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + warnings=warnings, + ) + + @override + def __str__(self) -> str: + # mypy complains about an invalid self arg + return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # type: ignore[misc] + + # Override the 'construct' method in a way that supports recursive parsing without validation. + # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836. + @classmethod + @override + def construct( # pyright: ignore[reportIncompatibleMethodOverride] + __cls: Type[ModelT], + _fields_set: set[str] | None = None, + **values: object, + ) -> ModelT: + m = __cls.__new__(__cls) + fields_values: dict[str, object] = {} + + config = get_model_config(__cls) + populate_by_name = ( + config.allow_population_by_field_name + if isinstance(config, _ConfigProtocol) + else config.get("populate_by_name") + ) + + if _fields_set is None: + _fields_set = set() + + model_fields = get_model_fields(__cls) + for name, field in model_fields.items(): + key = field.alias + if key is None or (key not in values and populate_by_name): + key = name + + if key in values: + fields_values[name] = _construct_field(value=values[key], field=field, key=key) + _fields_set.add(name) + else: + fields_values[name] = field_get_default(field) + + extra_field_type = _get_extra_fields_type(__cls) + + _extra = {} + for key, value in values.items(): + if key not in model_fields: + parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value + + if PYDANTIC_V1: + _fields_set.add(key) + fields_values[key] = parsed + else: + _extra[key] = parsed + + object.__setattr__(m, "__dict__", fields_values) + + if PYDANTIC_V1: + # init_private_attributes() does not exist in v2 + m._init_private_attributes() # type: ignore + + # copied from Pydantic v1's `construct()` method + object.__setattr__(m, "__fields_set__", _fields_set) + else: + # these properties are copied from Pydantic's `model_construct()` method + object.__setattr__(m, "__pydantic_private__", None) + object.__setattr__(m, "__pydantic_extra__", _extra) + object.__setattr__(m, "__pydantic_fields_set__", _fields_set) + + return m + + if not TYPE_CHECKING: + # type checkers incorrectly complain about this assignment + # because the type signatures are technically different + # although not in practice + model_construct = construct + + if PYDANTIC_V1: + # we define aliases for some of the new pydantic v2 methods so + # that we can just document these methods without having to specify + # a specific pydantic version as some users may not know which + # pydantic version they are currently using + + @override + def model_dump( + self, + *, + mode: Literal["json", "python"] | str = "python", + include: IncEx | None = None, + exclude: IncEx | None = None, + context: Any | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal["none", "warn", "error"] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + ) -> dict[str, Any]: + """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump + + Generate a dictionary representation of the model, optionally specifying which fields to include or exclude. + + Args: + mode: The mode in which `to_python` should run. + If mode is 'json', the output will only contain JSON serializable types. + If mode is 'python', the output may contain non-JSON-serializable Python objects. + include: A set of fields to include in the output. + exclude: A set of fields to exclude from the output. + context: Additional context to pass to the serializer. + by_alias: Whether to use the field's alias in the dictionary key if defined. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value. + exclude_none: Whether to exclude fields that have a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + + Returns: + A dictionary representation of the model. + """ + if mode not in {"json", "python"}: + raise ValueError("mode must be either 'json' or 'python'") + if round_trip != False: + raise ValueError("round_trip is only supported in Pydantic v2") + if warnings != True: + raise ValueError("warnings is only supported in Pydantic v2") + if context is not None: + raise ValueError("context is only supported in Pydantic v2") + if serialize_as_any != False: + raise ValueError("serialize_as_any is only supported in Pydantic v2") + if fallback is not None: + raise ValueError("fallback is only supported in Pydantic v2") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") + dumped = super().dict( # pyright: ignore[reportDeprecated] + include=include, + exclude=exclude, + by_alias=by_alias if by_alias is not None else False, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + + return cast("dict[str, Any]", json_safe(dumped)) if mode == "json" else dumped + + @override + def model_dump_json( + self, + *, + indent: int | None = None, + ensure_ascii: bool = False, + include: IncEx | None = None, + exclude: IncEx | None = None, + context: Any | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal["none", "warn", "error"] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + ) -> str: + """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json + + Generates a JSON representation of the model using Pydantic's `to_json` method. + + Args: + indent: Indentation to use in the JSON output. If None is passed, the output will be compact. + include: Field(s) to include in the JSON output. Can take either a string or set of strings. + exclude: Field(s) to exclude from the JSON output. Can take either a string or set of strings. + by_alias: Whether to serialize using field aliases. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that have the default value. + exclude_none: Whether to exclude fields that have a value of `None`. + round_trip: Whether to use serialization/deserialization between JSON and class instance. + warnings: Whether to show any warnings that occurred during serialization. + + Returns: + A JSON string representation of the model. + """ + if round_trip != False: + raise ValueError("round_trip is only supported in Pydantic v2") + if warnings != True: + raise ValueError("warnings is only supported in Pydantic v2") + if context is not None: + raise ValueError("context is only supported in Pydantic v2") + if serialize_as_any != False: + raise ValueError("serialize_as_any is only supported in Pydantic v2") + if fallback is not None: + raise ValueError("fallback is only supported in Pydantic v2") + if ensure_ascii != False: + raise ValueError("ensure_ascii is only supported in Pydantic v2") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") + return super().json( # type: ignore[reportDeprecated] + indent=indent, + include=include, + exclude=exclude, + by_alias=by_alias if by_alias is not None else False, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + + +def _construct_field(value: object, field: FieldInfo, key: str) -> object: + if value is None: + return field_get_default(field) + + if PYDANTIC_V1: + type_ = cast(type, field.outer_type_) # type: ignore + else: + type_ = field.annotation # type: ignore + + if type_ is None: + raise RuntimeError(f"Unexpected field type is None for {key}") + + return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) + + +def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None: + if PYDANTIC_V1: + # TODO + return None + + schema = cls.__pydantic_core_schema__ + if schema["type"] == "model": + fields = schema["schema"] + if fields["type"] == "model-fields": + extras = fields.get("extras_schema") + if extras and "cls" in extras: + # mypy can't narrow the type + return extras["cls"] # type: ignore[no-any-return] + + return None + + +def is_basemodel(type_: type) -> bool: + """Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`""" + if is_union(type_): + for variant in get_args(type_): + if is_basemodel(variant): + return True + + return False + + return is_basemodel_type(type_) + + +def is_basemodel_type(type_: type) -> TypeGuard[type[BaseModel] | type[GenericModel]]: + origin = get_origin(type_) or type_ + if not inspect.isclass(origin): + return False + return issubclass(origin, BaseModel) or issubclass(origin, GenericModel) + + +def build( + base_model_cls: Callable[P, _BaseModelT], + *args: P.args, + **kwargs: P.kwargs, +) -> _BaseModelT: + """Construct a BaseModel class without validation. + + This is useful for cases where you need to instantiate a `BaseModel` + from an API response as this provides type-safe params which isn't supported + by helpers like `construct_type()`. + + ```py + build(MyModel, my_field_a="foo", my_field_b=123) + ``` + """ + if args: + raise TypeError( + "Received positional arguments which are not supported; Keyword arguments must be used instead", + ) + + return cast(_BaseModelT, construct_type(type_=base_model_cls, value=kwargs)) + + +def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T: + """Loose coercion to the expected type with construction of nested values. + + Note: the returned value from this function is not guaranteed to match the + given type. + """ + return cast(_T, construct_type(value=value, type_=type_)) + + +def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object: + """Loose coercion to the expected type with construction of nested values. + + If the given value does not match the expected type then it is returned as-is. + """ + + # store a reference to the original type we were given before we extract any inner + # types so that we can properly resolve forward references in `TypeAliasType` annotations + original_type = None + + # we allow `object` as the input type because otherwise, passing things like + # `Literal['value']` will be reported as a type error by type checkers + type_ = cast("type[object]", type_) + if is_type_alias_type(type_): + original_type = type_ # type: ignore[unreachable] + type_ = type_.__value__ # type: ignore[unreachable] + + # unwrap `Annotated[T, ...]` -> `T` + if metadata is not None and len(metadata) > 0: + meta: tuple[Any, ...] = tuple(metadata) + elif is_annotated_type(type_): + meta = get_args(type_)[1:] + type_ = extract_type_arg(type_, 0) + else: + meta = tuple() + + # we need to use the origin class for any types that are subscripted generics + # e.g. Dict[str, object] + origin = get_origin(type_) or type_ + args = get_args(type_) + + if is_union(origin): + try: + return validate_type(type_=cast("type[object]", original_type or type_), value=value) + except Exception: + pass + + # if the type is a discriminated union then we want to construct the right variant + # in the union, even if the data doesn't match exactly, otherwise we'd break code + # that relies on the constructed class types, e.g. + # + # class FooType: + # kind: Literal['foo'] + # value: str + # + # class BarType: + # kind: Literal['bar'] + # value: int + # + # without this block, if the data we get is something like `{'kind': 'bar', 'value': 'foo'}` then + # we'd end up constructing `FooType` when it should be `BarType`. + discriminator = _build_discriminated_union_meta(union=type_, meta_annotations=meta) + if discriminator and is_mapping(value): + variant_value = value.get(discriminator.field_alias_from or discriminator.field_name) + if variant_value and isinstance(variant_value, str): + variant_type = discriminator.mapping.get(variant_value) + if variant_type: + return construct_type(type_=variant_type, value=value) + + # if the data is not valid, use the first variant that doesn't fail while deserializing + for variant in args: + try: + return construct_type(value=value, type_=variant) + except Exception: + continue + + raise RuntimeError(f"Could not convert data into a valid instance of {type_}") + + if origin == dict: + if not is_mapping(value): + return value + + _, items_type = get_args(type_) # Dict[_, items_type] + return {key: construct_type(value=item, type_=items_type) for key, item in value.items()} + + if ( + not is_literal_type(type_) + and inspect.isclass(origin) + and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)) + ): + if is_list(value): + return [cast(Any, type_).construct(**entry) if is_mapping(entry) else entry for entry in value] + + if is_mapping(value): + if issubclass(type_, BaseModel): + return type_.construct(**value) # type: ignore[arg-type] + + return cast(Any, type_).construct(**value) + + if origin == list: + if not is_list(value): + return value + + inner_type = args[0] # List[inner_type] + return [construct_type(value=entry, type_=inner_type) for entry in value] + + if origin == float: + if isinstance(value, int): + coerced = float(value) + if coerced != value: + return value + return coerced + + return value + + if type_ == datetime: + try: + return parse_datetime(value) # type: ignore + except Exception: + return value + + if type_ == date: + try: + return parse_date(value) # type: ignore + except Exception: + return value + + return value + + +@runtime_checkable +class CachedDiscriminatorType(Protocol): + __discriminator__: DiscriminatorDetails + + +DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary() + + +class DiscriminatorDetails: + field_name: str + """The name of the discriminator field in the variant class, e.g. + + ```py + class Foo(BaseModel): + type: Literal['foo'] + ``` + + Will result in field_name='type' + """ + + field_alias_from: str | None + """The name of the discriminator field in the API response, e.g. + + ```py + class Foo(BaseModel): + type: Literal['foo'] = Field(alias='type_from_api') + ``` + + Will result in field_alias_from='type_from_api' + """ + + mapping: dict[str, type] + """Mapping of discriminator value to variant type, e.g. + + {'foo': FooVariant, 'bar': BarVariant} + """ + + def __init__( + self, + *, + mapping: dict[str, type], + discriminator_field: str, + discriminator_alias: str | None, + ) -> None: + self.mapping = mapping + self.field_name = discriminator_field + self.field_alias_from = discriminator_alias + + +def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None: + cached = DISCRIMINATOR_CACHE.get(union) + if cached is not None: + return cached + + discriminator_field_name: str | None = None + + for annotation in meta_annotations: + if isinstance(annotation, PropertyInfo) and annotation.discriminator is not None: + discriminator_field_name = annotation.discriminator + break + + if not discriminator_field_name: + return None + + mapping: dict[str, type] = {} + discriminator_alias: str | None = None + + for variant in get_args(union): + variant = strip_annotated_type(variant) + if is_basemodel_type(variant): + if PYDANTIC_V1: + field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + if not field_info: + continue + + # Note: if one variant defines an alias then they all should + discriminator_alias = field_info.alias + + if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): + for entry in get_args(annotation): + if isinstance(entry, str): + mapping[entry] = variant + else: + field = _extract_field_schema_pv2(variant, discriminator_field_name) + if not field: + continue + + # Note: if one variant defines an alias then they all should + discriminator_alias = field.get("serialization_alias") + + field_schema = field["schema"] + + if field_schema["type"] == "literal": + for entry in cast("LiteralSchema", field_schema)["expected"]: + if isinstance(entry, str): + mapping[entry] = variant + + if not mapping: + return None + + details = DiscriminatorDetails( + mapping=mapping, + discriminator_field=discriminator_field_name, + discriminator_alias=discriminator_alias, + ) + DISCRIMINATOR_CACHE.setdefault(union, details) + return details + + +def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelField | None: + schema = model.__pydantic_core_schema__ + if schema["type"] == "definitions": + schema = schema["schema"] + + if schema["type"] != "model": + return None + + schema = cast("ModelSchema", schema) + fields_schema = schema["schema"] + if fields_schema["type"] != "model-fields": + return None + + fields_schema = cast("ModelFieldsSchema", fields_schema) + field = fields_schema["fields"].get(field_name) + if not field: + return None + + return cast("ModelField", field) # pyright: ignore[reportUnnecessaryCast] + + +def validate_type(*, type_: type[_T], value: object) -> _T: + """Strict validation that the given value matches the expected type""" + if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel): + return cast(_T, parse_obj(type_, value)) + + return cast(_T, _validate_non_model_type(type_=type_, value=value)) + + +def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None: + """Add a pydantic config for the given type. + + Note: this is a no-op on Pydantic v1. + """ + setattr(typ, "__pydantic_config__", config) # noqa: B010 + + +# our use of subclassing here causes weirdness for type checkers, +# so we just pretend that we don't subclass +if TYPE_CHECKING: + GenericModel = BaseModel +else: + + class GenericModel(BaseGenericModel, BaseModel): + pass + + +if not PYDANTIC_V1: + from pydantic import TypeAdapter as _TypeAdapter + + _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter)) + + if TYPE_CHECKING: + from pydantic import TypeAdapter + else: + TypeAdapter = _CachedTypeAdapter + + def _validate_non_model_type(*, type_: type[_T], value: object) -> _T: + return TypeAdapter(type_).validate_python(value) + +elif not TYPE_CHECKING: # TODO: condition is weird + + class RootModel(GenericModel, Generic[_T]): + """Used as a placeholder to easily convert runtime types to a Pydantic format + to provide validation. + + For example: + ```py + validated = RootModel[int](__root__="5").__root__ + # validated: 5 + ``` + """ + + __root__: _T + + def _validate_non_model_type(*, type_: type[_T], value: object) -> _T: + model = _create_pydantic_model(type_).validate(value) + return cast(_T, model.__root__) + + def _create_pydantic_model(type_: _T) -> Type[RootModel[_T]]: + return RootModel[type_] # type: ignore + + +class FinalRequestOptionsInput(TypedDict, total=False): + method: Required[str] + url: Required[str] + params: Query + headers: Headers + max_retries: int + timeout: float | Timeout | None + files: HttpxRequestFiles | None + idempotency_key: str + content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] + json_data: Body + extra_json: AnyMapping + follow_redirects: bool + + +@final +class FinalRequestOptions(pydantic.BaseModel): + method: str + url: str + params: Query = {} + headers: Union[Headers, NotGiven] = NotGiven() + max_retries: Union[int, NotGiven] = NotGiven() + timeout: Union[float, Timeout, None, NotGiven] = NotGiven() + files: Union[HttpxRequestFiles, None] = None + idempotency_key: Union[str, None] = None + post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() + follow_redirects: Union[bool, None] = None + + content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None + # It should be noted that we cannot use `json` here as that would override + # a BaseModel method in an incompatible fashion. + json_data: Union[Body, None] = None + extra_json: Union[AnyMapping, None] = None + + if PYDANTIC_V1: + + class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] + arbitrary_types_allowed: bool = True + else: + model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) + + def get_max_retries(self, max_retries: int) -> int: + if isinstance(self.max_retries, NotGiven): + return max_retries + return self.max_retries + + def _strip_raw_response_header(self) -> None: + if not is_given(self.headers): + return + + if self.headers.get(RAW_RESPONSE_HEADER): + self.headers = {**self.headers} + self.headers.pop(RAW_RESPONSE_HEADER) + + # override the `construct` method so that we can run custom transformations. + # this is necessary as we don't want to do any actual runtime type checking + # (which means we can't use validators) but we do want to ensure that `NotGiven` + # values are not present + # + # type ignore required because we're adding explicit types to `**values` + @classmethod + def construct( # type: ignore + cls, + _fields_set: set[str] | None = None, + **values: Unpack[FinalRequestOptionsInput], + ) -> FinalRequestOptions: + kwargs: dict[str, Any] = { + # we unconditionally call `strip_not_given` on any value + # as it will just ignore any non-mapping types + key: strip_not_given(value) + for key, value in values.items() + } + if PYDANTIC_V1: + return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] + return super().model_construct(_fields_set, **kwargs) + + if not TYPE_CHECKING: + # type checkers incorrectly complain about this assignment + model_construct = construct diff --git a/src/gcore/_qs.py b/src/gcore/_qs.py new file mode 100644 index 00000000..ada6fd3f --- /dev/null +++ b/src/gcore/_qs.py @@ -0,0 +1,150 @@ +from __future__ import annotations + +from typing import Any, List, Tuple, Union, Mapping, TypeVar +from urllib.parse import parse_qs, urlencode +from typing_extensions import Literal, get_args + +from ._types import NotGiven, not_given +from ._utils import flatten + +_T = TypeVar("_T") + + +ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] +NestedFormat = Literal["dots", "brackets"] + +PrimitiveData = Union[str, int, float, bool, None] +# this should be Data = Union[PrimitiveData, "List[Data]", "Tuple[Data]", "Mapping[str, Data]"] +# https://github.com/microsoft/pyright/issues/3555 +Data = Union[PrimitiveData, List[Any], Tuple[Any], "Mapping[str, Any]"] +Params = Mapping[str, Data] + + +class Querystring: + array_format: ArrayFormat + nested_format: NestedFormat + + def __init__( + self, + *, + array_format: ArrayFormat = "repeat", + nested_format: NestedFormat = "brackets", + ) -> None: + self.array_format = array_format + self.nested_format = nested_format + + def parse(self, query: str) -> Mapping[str, object]: + # Note: custom format syntax is not supported yet + return parse_qs(query) + + def stringify( + self, + params: Params, + *, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, + ) -> str: + return urlencode( + self.stringify_items( + params, + array_format=array_format, + nested_format=nested_format, + ) + ) + + def stringify_items( + self, + params: Params, + *, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, + ) -> list[tuple[str, str]]: + opts = Options( + qs=self, + array_format=array_format, + nested_format=nested_format, + ) + return flatten([self._stringify_item(key, value, opts) for key, value in params.items()]) + + def _stringify_item( + self, + key: str, + value: Data, + opts: Options, + ) -> list[tuple[str, str]]: + if isinstance(value, Mapping): + items: list[tuple[str, str]] = [] + nested_format = opts.nested_format + for subkey, subvalue in value.items(): + items.extend( + self._stringify_item( + # TODO: error if unknown format + f"{key}.{subkey}" if nested_format == "dots" else f"{key}[{subkey}]", + subvalue, + opts, + ) + ) + return items + + if isinstance(value, (list, tuple)): + array_format = opts.array_format + if array_format == "comma": + return [ + ( + key, + ",".join(self._primitive_value_to_str(item) for item in value if item is not None), + ), + ] + elif array_format == "repeat": + items = [] + for item in value: + items.extend(self._stringify_item(key, item, opts)) + return items + elif array_format == "indices": + raise NotImplementedError("The array indices format is not supported yet") + elif array_format == "brackets": + items = [] + key = key + "[]" + for item in value: + items.extend(self._stringify_item(key, item, opts)) + return items + else: + raise NotImplementedError( + f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}" + ) + + serialised = self._primitive_value_to_str(value) + if not serialised: + return [] + return [(key, serialised)] + + def _primitive_value_to_str(self, value: PrimitiveData) -> str: + # copied from httpx + if value is True: + return "true" + elif value is False: + return "false" + elif value is None: + return "" + return str(value) + + +_qs = Querystring() +parse = _qs.parse +stringify = _qs.stringify +stringify_items = _qs.stringify_items + + +class Options: + array_format: ArrayFormat + nested_format: NestedFormat + + def __init__( + self, + qs: Querystring = _qs, + *, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, + ) -> None: + self.array_format = qs.array_format if isinstance(array_format, NotGiven) else array_format + self.nested_format = qs.nested_format if isinstance(nested_format, NotGiven) else nested_format diff --git a/src/gcore/_resource.py b/src/gcore/_resource.py new file mode 100644 index 00000000..4bfc5b68 --- /dev/null +++ b/src/gcore/_resource.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import time +from typing import TYPE_CHECKING + +import anyio + +if TYPE_CHECKING: + from ._client import Gcore, AsyncGcore + + +class SyncAPIResource: + _client: Gcore + + def __init__(self, client: Gcore) -> None: + self._client = client + self._get = client.get + self._post = client.post + self._patch = client.patch + self._put = client.put + self._delete = client.delete + self._get_api_list = client.get_api_list + + def _sleep(self, seconds: float) -> None: + time.sleep(seconds) + + +class AsyncAPIResource: + _client: AsyncGcore + + def __init__(self, client: AsyncGcore) -> None: + self._client = client + self._get = client.get + self._post = client.post + self._patch = client.patch + self._put = client.put + self._delete = client.delete + self._get_api_list = client.get_api_list + + async def _sleep(self, seconds: float) -> None: + await anyio.sleep(seconds) diff --git a/src/gcore/_response.py b/src/gcore/_response.py new file mode 100644 index 00000000..f8a69959 --- /dev/null +++ b/src/gcore/_response.py @@ -0,0 +1,830 @@ +from __future__ import annotations + +import os +import inspect +import logging +import datetime +import functools +from types import TracebackType +from typing import ( + TYPE_CHECKING, + Any, + Union, + Generic, + TypeVar, + Callable, + Iterator, + AsyncIterator, + cast, + overload, +) +from typing_extensions import Awaitable, ParamSpec, override, get_origin + +import anyio +import httpx +import pydantic + +from ._types import NoneType +from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type, extract_type_var_from_base +from ._models import BaseModel, is_basemodel +from ._constants import RAW_RESPONSE_HEADER, OVERRIDE_CAST_TO_HEADER +from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type +from ._exceptions import GcoreError, APIResponseValidationError + +if TYPE_CHECKING: + from ._models import FinalRequestOptions + from ._base_client import BaseClient + + +P = ParamSpec("P") +R = TypeVar("R") +_T = TypeVar("_T") +_APIResponseT = TypeVar("_APIResponseT", bound="APIResponse[Any]") +_AsyncAPIResponseT = TypeVar("_AsyncAPIResponseT", bound="AsyncAPIResponse[Any]") + +log: logging.Logger = logging.getLogger(__name__) + + +class BaseAPIResponse(Generic[R]): + _cast_to: type[R] + _client: BaseClient[Any, Any] + _parsed_by_type: dict[type[Any], Any] + _is_sse_stream: bool + _stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None + _options: FinalRequestOptions + + http_response: httpx.Response + + retries_taken: int + """The number of retries made. If no retries happened this will be `0`""" + + def __init__( + self, + *, + raw: httpx.Response, + cast_to: type[R], + client: BaseClient[Any, Any], + stream: bool, + stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, + options: FinalRequestOptions, + retries_taken: int = 0, + ) -> None: + self._cast_to = cast_to + self._client = client + self._parsed_by_type = {} + self._is_sse_stream = stream + self._stream_cls = stream_cls + self._options = options + self.http_response = raw + self.retries_taken = retries_taken + + @property + def headers(self) -> httpx.Headers: + return self.http_response.headers + + @property + def http_request(self) -> httpx.Request: + """Returns the httpx Request instance associated with the current response.""" + return self.http_response.request + + @property + def status_code(self) -> int: + return self.http_response.status_code + + @property + def url(self) -> httpx.URL: + """Returns the URL for which the request was made.""" + return self.http_response.url + + @property + def method(self) -> str: + return self.http_request.method + + @property + def http_version(self) -> str: + return self.http_response.http_version + + @property + def elapsed(self) -> datetime.timedelta: + """The time taken for the complete request/response cycle to complete.""" + return self.http_response.elapsed + + @property + def is_closed(self) -> bool: + """Whether or not the response body has been closed. + + If this is False then there is response data that has not been read yet. + You must either fully consume the response body or call `.close()` + before discarding the response to prevent resource leaks. + """ + return self.http_response.is_closed + + @override + def __repr__(self) -> str: + return ( + f"<{self.__class__.__name__} [{self.status_code} {self.http_response.reason_phrase}] type={self._cast_to}>" + ) + + def _parse(self, *, to: type[_T] | None = None) -> R | _T: + cast_to = to if to is not None else self._cast_to + + # unwrap `TypeAlias('Name', T)` -> `T` + if is_type_alias_type(cast_to): + cast_to = cast_to.__value__ # type: ignore[unreachable] + + # unwrap `Annotated[T, ...]` -> `T` + if cast_to and is_annotated_type(cast_to): + cast_to = extract_type_arg(cast_to, 0) + + origin = get_origin(cast_to) or cast_to + + if self._is_sse_stream: + if to: + if not is_stream_class_type(to): + raise TypeError(f"Expected custom parse type to be a subclass of {Stream} or {AsyncStream}") + + return cast( + _T, + to( + cast_to=extract_stream_chunk_type( + to, + failure_message="Expected custom stream type to be passed with a type argument, e.g. Stream[ChunkType]", + ), + response=self.http_response, + client=cast(Any, self._client), + ), + ) + + if self._stream_cls: + return cast( + R, + self._stream_cls( + cast_to=extract_stream_chunk_type(self._stream_cls), + response=self.http_response, + client=cast(Any, self._client), + ), + ) + + stream_cls = cast("type[Stream[Any]] | type[AsyncStream[Any]] | None", self._client._default_stream_cls) + if stream_cls is None: + raise MissingStreamClassError() + + return cast( + R, + stream_cls( + cast_to=cast_to, + response=self.http_response, + client=cast(Any, self._client), + ), + ) + + if cast_to is NoneType: + return cast(R, None) + + response = self.http_response + if cast_to == str: + return cast(R, response.text) + + if cast_to == bytes: + return cast(R, response.content) + + if cast_to == int: + return cast(R, int(response.text)) + + if cast_to == float: + return cast(R, float(response.text)) + + if cast_to == bool: + return cast(R, response.text.lower() == "true") + + if origin == APIResponse: + raise RuntimeError("Unexpected state - cast_to is `APIResponse`") + + if inspect.isclass(origin) and issubclass(origin, httpx.Response): + # Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response + # and pass that class to our request functions. We cannot change the variance to be either + # covariant or contravariant as that makes our usage of ResponseT illegal. We could construct + # the response class ourselves but that is something that should be supported directly in httpx + # as it would be easy to incorrectly construct the Response object due to the multitude of arguments. + if cast_to != httpx.Response: + raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`") + return cast(R, response) + + if ( + inspect.isclass( + origin # pyright: ignore[reportUnknownArgumentType] + ) + and not issubclass(origin, BaseModel) + and issubclass(origin, pydantic.BaseModel) + ): + raise TypeError("Pydantic models must subclass our base model type, e.g. `from gcore import BaseModel`") + + if ( + cast_to is not object + and not origin is list + and not origin is dict + and not origin is Union + and not issubclass(origin, BaseModel) + ): + raise RuntimeError( + f"Unsupported type, expected {cast_to} to be a subclass of {BaseModel}, {dict}, {list}, {Union}, {NoneType}, {str} or {httpx.Response}." + ) + + # split is required to handle cases where additional information is included + # in the response, e.g. application/json; charset=utf-8 + content_type, *_ = response.headers.get("content-type", "*").split(";") + if not content_type.endswith("json"): + if is_basemodel(cast_to): + try: + data = response.json() + except Exception as exc: + log.debug("Could not read JSON from response data due to %s - %s", type(exc), exc) + else: + return self._client._process_response_data( + data=data, + cast_to=cast_to, # type: ignore + response=response, + ) + + if self._client._strict_response_validation: + raise APIResponseValidationError( + response=response, + message=f"Expected Content-Type response header to be `application/json` but received `{content_type}` instead.", + body=response.text, + ) + + # If the API responds with content that isn't JSON then we just return + # the (decoded) text without performing any parsing so that you can still + # handle the response however you need to. + return response.text # type: ignore + + data = response.json() + + return self._client._process_response_data( + data=data, + cast_to=cast_to, # type: ignore + response=response, + ) + + +class APIResponse(BaseAPIResponse[R]): + @overload + def parse(self, *, to: type[_T]) -> _T: ... + + @overload + def parse(self) -> R: ... + + def parse(self, *, to: type[_T] | None = None) -> R | _T: + """Returns the rich python representation of this response's data. + + For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. + + You can customise the type that the response is parsed into through + the `to` argument, e.g. + + ```py + from gcore import BaseModel + + + class MyModel(BaseModel): + foo: str + + + obj = response.parse(to=MyModel) + print(obj.foo) + ``` + + We support parsing: + - `BaseModel` + - `dict` + - `list` + - `Union` + - `str` + - `int` + - `float` + - `httpx.Response` + """ + cache_key = to if to is not None else self._cast_to + cached = self._parsed_by_type.get(cache_key) + if cached is not None: + return cached # type: ignore[no-any-return] + + if not self._is_sse_stream: + self.read() + + parsed = self._parse(to=to) + if is_given(self._options.post_parser): + parsed = self._options.post_parser(parsed) + + self._parsed_by_type[cache_key] = parsed + return parsed + + def read(self) -> bytes: + """Read and return the binary response content.""" + try: + return self.http_response.read() + except httpx.StreamConsumed as exc: + # The default error raised by httpx isn't very + # helpful in our case so we re-raise it with + # a different error message. + raise StreamAlreadyConsumed() from exc + + def text(self) -> str: + """Read and decode the response content into a string.""" + self.read() + return self.http_response.text + + def json(self) -> object: + """Read and decode the JSON response content.""" + self.read() + return self.http_response.json() + + def close(self) -> None: + """Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + self.http_response.close() + + def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]: + """ + A byte-iterator over the decoded response content. + + This automatically handles gzip, deflate and brotli encoded responses. + """ + for chunk in self.http_response.iter_bytes(chunk_size): + yield chunk + + def iter_text(self, chunk_size: int | None = None) -> Iterator[str]: + """A str-iterator over the decoded response content + that handles both gzip, deflate, etc but also detects the content's + string encoding. + """ + for chunk in self.http_response.iter_text(chunk_size): + yield chunk + + def iter_lines(self) -> Iterator[str]: + """Like `iter_text()` but will only yield chunks for each line""" + for chunk in self.http_response.iter_lines(): + yield chunk + + +class AsyncAPIResponse(BaseAPIResponse[R]): + @overload + async def parse(self, *, to: type[_T]) -> _T: ... + + @overload + async def parse(self) -> R: ... + + async def parse(self, *, to: type[_T] | None = None) -> R | _T: + """Returns the rich python representation of this response's data. + + For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. + + You can customise the type that the response is parsed into through + the `to` argument, e.g. + + ```py + from gcore import BaseModel + + + class MyModel(BaseModel): + foo: str + + + obj = response.parse(to=MyModel) + print(obj.foo) + ``` + + We support parsing: + - `BaseModel` + - `dict` + - `list` + - `Union` + - `str` + - `httpx.Response` + """ + cache_key = to if to is not None else self._cast_to + cached = self._parsed_by_type.get(cache_key) + if cached is not None: + return cached # type: ignore[no-any-return] + + if not self._is_sse_stream: + await self.read() + + parsed = self._parse(to=to) + if is_given(self._options.post_parser): + parsed = self._options.post_parser(parsed) + + self._parsed_by_type[cache_key] = parsed + return parsed + + async def read(self) -> bytes: + """Read and return the binary response content.""" + try: + return await self.http_response.aread() + except httpx.StreamConsumed as exc: + # the default error raised by httpx isn't very + # helpful in our case so we re-raise it with + # a different error message + raise StreamAlreadyConsumed() from exc + + async def text(self) -> str: + """Read and decode the response content into a string.""" + await self.read() + return self.http_response.text + + async def json(self) -> object: + """Read and decode the JSON response content.""" + await self.read() + return self.http_response.json() + + async def close(self) -> None: + """Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + await self.http_response.aclose() + + async def iter_bytes(self, chunk_size: int | None = None) -> AsyncIterator[bytes]: + """ + A byte-iterator over the decoded response content. + + This automatically handles gzip, deflate and brotli encoded responses. + """ + async for chunk in self.http_response.aiter_bytes(chunk_size): + yield chunk + + async def iter_text(self, chunk_size: int | None = None) -> AsyncIterator[str]: + """A str-iterator over the decoded response content + that handles both gzip, deflate, etc but also detects the content's + string encoding. + """ + async for chunk in self.http_response.aiter_text(chunk_size): + yield chunk + + async def iter_lines(self) -> AsyncIterator[str]: + """Like `iter_text()` but will only yield chunks for each line""" + async for chunk in self.http_response.aiter_lines(): + yield chunk + + +class BinaryAPIResponse(APIResponse[bytes]): + """Subclass of APIResponse providing helpers for dealing with binary data. + + Note: If you want to stream the response data instead of eagerly reading it + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + + def write_to_file( + self, + file: str | os.PathLike[str], + ) -> None: + """Write the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + + Note: if you want to stream the data to the file instead of writing + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + with open(file, mode="wb") as f: + for data in self.iter_bytes(): + f.write(data) + + +class AsyncBinaryAPIResponse(AsyncAPIResponse[bytes]): + """Subclass of APIResponse providing helpers for dealing with binary data. + + Note: If you want to stream the response data instead of eagerly reading it + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + + async def write_to_file( + self, + file: str | os.PathLike[str], + ) -> None: + """Write the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + + Note: if you want to stream the data to the file instead of writing + all at once then you should use `.with_streaming_response` when making + the API request, e.g. `.with_streaming_response.get_binary_response()` + """ + path = anyio.Path(file) + async with await path.open(mode="wb") as f: + async for data in self.iter_bytes(): + await f.write(data) + + +class StreamedBinaryAPIResponse(APIResponse[bytes]): + def stream_to_file( + self, + file: str | os.PathLike[str], + *, + chunk_size: int | None = None, + ) -> None: + """Streams the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + """ + with open(file, mode="wb") as f: + for data in self.iter_bytes(chunk_size): + f.write(data) + + +class AsyncStreamedBinaryAPIResponse(AsyncAPIResponse[bytes]): + async def stream_to_file( + self, + file: str | os.PathLike[str], + *, + chunk_size: int | None = None, + ) -> None: + """Streams the output to the given file. + + Accepts a filename or any path-like object, e.g. pathlib.Path + """ + path = anyio.Path(file) + async with await path.open(mode="wb") as f: + async for data in self.iter_bytes(chunk_size): + await f.write(data) + + +class MissingStreamClassError(TypeError): + def __init__(self) -> None: + super().__init__( + "The `stream` argument was set to `True` but the `stream_cls` argument was not given. See `gcore._streaming` for reference", + ) + + +class StreamAlreadyConsumed(GcoreError): + """ + Attempted to read or stream content, but the content has already + been streamed. + + This can happen if you use a method like `.iter_lines()` and then attempt + to read th entire response body afterwards, e.g. + + ```py + response = await client.post(...) + async for line in response.iter_lines(): + ... # do something with `line` + + content = await response.read() + # ^ error + ``` + + If you want this behaviour you'll need to either manually accumulate the response + content or call `await response.read()` before iterating over the stream. + """ + + def __init__(self) -> None: + message = ( + "Attempted to read or stream some content, but the content has " + "already been streamed. " + "This could be due to attempting to stream the response " + "content more than once." + "\n\n" + "You can fix this by manually accumulating the response content while streaming " + "or by calling `.read()` before starting to stream." + ) + super().__init__(message) + + +class ResponseContextManager(Generic[_APIResponseT]): + """Context manager for ensuring that a request is not made + until it is entered and that the response will always be closed + when the context manager exits + """ + + def __init__(self, request_func: Callable[[], _APIResponseT]) -> None: + self._request_func = request_func + self.__response: _APIResponseT | None = None + + def __enter__(self) -> _APIResponseT: + self.__response = self._request_func() + return self.__response + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + if self.__response is not None: + self.__response.close() + + +class AsyncResponseContextManager(Generic[_AsyncAPIResponseT]): + """Context manager for ensuring that a request is not made + until it is entered and that the response will always be closed + when the context manager exits + """ + + def __init__(self, api_request: Awaitable[_AsyncAPIResponseT]) -> None: + self._api_request = api_request + self.__response: _AsyncAPIResponseT | None = None + + async def __aenter__(self) -> _AsyncAPIResponseT: + self.__response = await self._api_request + return self.__response + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + if self.__response is not None: + await self.__response.close() + + +def to_streamed_response_wrapper(func: Callable[P, R]) -> Callable[P, ResponseContextManager[APIResponse[R]]]: + """Higher order function that takes one of our bound API methods and wraps it + to support streaming and returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[APIResponse[R]]: + extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + + kwargs["extra_headers"] = extra_headers + + make_request = functools.partial(func, *args, **kwargs) + + return ResponseContextManager(cast(Callable[[], APIResponse[R]], make_request)) + + return wrapped + + +def async_to_streamed_response_wrapper( + func: Callable[P, Awaitable[R]], +) -> Callable[P, AsyncResponseContextManager[AsyncAPIResponse[R]]]: + """Higher order function that takes one of our bound API methods and wraps it + to support streaming and returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[AsyncAPIResponse[R]]: + extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + + kwargs["extra_headers"] = extra_headers + + make_request = func(*args, **kwargs) + + return AsyncResponseContextManager(cast(Awaitable[AsyncAPIResponse[R]], make_request)) + + return wrapped + + +def to_custom_streamed_response_wrapper( + func: Callable[P, object], + response_cls: type[_APIResponseT], +) -> Callable[P, ResponseContextManager[_APIResponseT]]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support streaming and returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[_APIResponseT]: + extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + make_request = functools.partial(func, *args, **kwargs) + + return ResponseContextManager(cast(Callable[[], _APIResponseT], make_request)) + + return wrapped + + +def async_to_custom_streamed_response_wrapper( + func: Callable[P, Awaitable[object]], + response_cls: type[_AsyncAPIResponseT], +) -> Callable[P, AsyncResponseContextManager[_AsyncAPIResponseT]]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support streaming and returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[_AsyncAPIResponseT]: + extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "stream" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + make_request = func(*args, **kwargs) + + return AsyncResponseContextManager(cast(Awaitable[_AsyncAPIResponseT], make_request)) + + return wrapped + + +def to_raw_response_wrapper(func: Callable[P, R]) -> Callable[P, APIResponse[R]]: + """Higher order function that takes one of our bound API methods and wraps it + to support returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> APIResponse[R]: + extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + + kwargs["extra_headers"] = extra_headers + + return cast(APIResponse[R], func(*args, **kwargs)) + + return wrapped + + +def async_to_raw_response_wrapper(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[AsyncAPIResponse[R]]]: + """Higher order function that takes one of our bound API methods and wraps it + to support returning the raw `APIResponse` object directly. + """ + + @functools.wraps(func) + async def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncAPIResponse[R]: + extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + + kwargs["extra_headers"] = extra_headers + + return cast(AsyncAPIResponse[R], await func(*args, **kwargs)) + + return wrapped + + +def to_custom_raw_response_wrapper( + func: Callable[P, object], + response_cls: type[_APIResponseT], +) -> Callable[P, _APIResponseT]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> _APIResponseT: + extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + return cast(_APIResponseT, func(*args, **kwargs)) + + return wrapped + + +def async_to_custom_raw_response_wrapper( + func: Callable[P, Awaitable[object]], + response_cls: type[_AsyncAPIResponseT], +) -> Callable[P, Awaitable[_AsyncAPIResponseT]]: + """Higher order function that takes one of our bound API methods and an `APIResponse` class + and wraps the method to support returning the given response class directly. + + Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` + """ + + @functools.wraps(func) + def wrapped(*args: P.args, **kwargs: P.kwargs) -> Awaitable[_AsyncAPIResponseT]: + extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} + extra_headers[RAW_RESPONSE_HEADER] = "raw" + extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls + + kwargs["extra_headers"] = extra_headers + + return cast(Awaitable[_AsyncAPIResponseT], func(*args, **kwargs)) + + return wrapped + + +def extract_response_type(typ: type[BaseAPIResponse[Any]]) -> type: + """Given a type like `APIResponse[T]`, returns the generic type variable `T`. + + This also handles the case where a concrete subclass is given, e.g. + ```py + class MyResponse(APIResponse[bytes]): + ... + + extract_response_type(MyResponse) -> bytes + ``` + """ + return extract_type_var_from_base( + typ, + generic_bases=cast("tuple[type, ...]", (BaseAPIResponse, APIResponse, AsyncAPIResponse)), + index=0, + ) diff --git a/src/gcore/_streaming.py b/src/gcore/_streaming.py new file mode 100644 index 00000000..82ff9d32 --- /dev/null +++ b/src/gcore/_streaming.py @@ -0,0 +1,333 @@ +# Note: initially copied from https://github.com/florimondmanca/httpx-sse/blob/master/src/httpx_sse/_decoders.py +from __future__ import annotations + +import json +import inspect +from types import TracebackType +from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, AsyncIterator, cast +from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable + +import httpx + +from ._utils import extract_type_var_from_base + +if TYPE_CHECKING: + from ._client import Gcore, AsyncGcore + + +_T = TypeVar("_T") + + +class Stream(Generic[_T]): + """Provides the core interface to iterate over a synchronous stream response.""" + + response: httpx.Response + + _decoder: SSEBytesDecoder + + def __init__( + self, + *, + cast_to: type[_T], + response: httpx.Response, + client: Gcore, + ) -> None: + self.response = response + self._cast_to = cast_to + self._client = client + self._decoder = client._make_sse_decoder() + self._iterator = self.__stream__() + + def __next__(self) -> _T: + return self._iterator.__next__() + + def __iter__(self) -> Iterator[_T]: + for item in self._iterator: + yield item + + def _iter_events(self) -> Iterator[ServerSentEvent]: + yield from self._decoder.iter_bytes(self.response.iter_bytes()) + + def __stream__(self) -> Iterator[_T]: + cast_to = cast(Any, self._cast_to) + response = self.response + process_data = self._client._process_response_data + iterator = self._iter_events() + + try: + for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + response.close() + + def __enter__(self) -> Self: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.close() + + def close(self) -> None: + """ + Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + self.response.close() + + +class AsyncStream(Generic[_T]): + """Provides the core interface to iterate over an asynchronous stream response.""" + + response: httpx.Response + + _decoder: SSEDecoder | SSEBytesDecoder + + def __init__( + self, + *, + cast_to: type[_T], + response: httpx.Response, + client: AsyncGcore, + ) -> None: + self.response = response + self._cast_to = cast_to + self._client = client + self._decoder = client._make_sse_decoder() + self._iterator = self.__stream__() + + async def __anext__(self) -> _T: + return await self._iterator.__anext__() + + async def __aiter__(self) -> AsyncIterator[_T]: + async for item in self._iterator: + yield item + + async def _iter_events(self) -> AsyncIterator[ServerSentEvent]: + async for sse in self._decoder.aiter_bytes(self.response.aiter_bytes()): + yield sse + + async def __stream__(self) -> AsyncIterator[_T]: + cast_to = cast(Any, self._cast_to) + response = self.response + process_data = self._client._process_response_data + iterator = self._iter_events() + + try: + async for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + await response.aclose() + + async def __aenter__(self) -> Self: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + await self.close() + + async def close(self) -> None: + """ + Close the response and release the connection. + + Automatically called if the response body is read to completion. + """ + await self.response.aclose() + + +class ServerSentEvent: + def __init__( + self, + *, + event: str | None = None, + data: str | None = None, + id: str | None = None, + retry: int | None = None, + ) -> None: + if data is None: + data = "" + + self._id = id + self._data = data + self._event = event or None + self._retry = retry + + @property + def event(self) -> str | None: + return self._event + + @property + def id(self) -> str | None: + return self._id + + @property + def retry(self) -> int | None: + return self._retry + + @property + def data(self) -> str: + return self._data + + def json(self) -> Any: + return json.loads(self.data) + + @override + def __repr__(self) -> str: + return f"ServerSentEvent(event={self.event}, data={self.data}, id={self.id}, retry={self.retry})" + + +class SSEDecoder: + _data: list[str] + _event: str | None + _retry: int | None + _last_event_id: str | None + + def __init__(self) -> None: + self._event = None + self._data = [] + self._last_event_id = None + self._retry = None + + def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]: + """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" + for chunk in self._iter_chunks(iterator): + # Split before decoding so splitlines() only uses \r and \n + for raw_line in chunk.splitlines(): + line = raw_line.decode("utf-8") + sse = self.decode(line) + if sse: + yield sse + + def _iter_chunks(self, iterator: Iterator[bytes]) -> Iterator[bytes]: + """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" + data = b"" + for chunk in iterator: + for line in chunk.splitlines(keepends=True): + data += line + if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): + yield data + data = b"" + if data: + yield data + + async def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]: + """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" + async for chunk in self._aiter_chunks(iterator): + # Split before decoding so splitlines() only uses \r and \n + for raw_line in chunk.splitlines(): + line = raw_line.decode("utf-8") + sse = self.decode(line) + if sse: + yield sse + + async def _aiter_chunks(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[bytes]: + """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" + data = b"" + async for chunk in iterator: + for line in chunk.splitlines(keepends=True): + data += line + if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): + yield data + data = b"" + if data: + yield data + + def decode(self, line: str) -> ServerSentEvent | None: + # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501 + + if not line: + if not self._event and not self._data and not self._last_event_id and self._retry is None: + return None + + sse = ServerSentEvent( + event=self._event, + data="\n".join(self._data), + id=self._last_event_id, + retry=self._retry, + ) + + # NOTE: as per the SSE spec, do not reset last_event_id. + self._event = None + self._data = [] + self._retry = None + + return sse + + if line.startswith(":"): + return None + + fieldname, _, value = line.partition(":") + + if value.startswith(" "): + value = value[1:] + + if fieldname == "event": + self._event = value + elif fieldname == "data": + self._data.append(value) + elif fieldname == "id": + if "\0" in value: + pass + else: + self._last_event_id = value + elif fieldname == "retry": + try: + self._retry = int(value) + except (TypeError, ValueError): + pass + else: + pass # Field is ignored. + + return None + + +@runtime_checkable +class SSEBytesDecoder(Protocol): + def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]: + """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" + ... + + def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]: + """Given an async iterator that yields raw binary data, iterate over it & yield every event encountered""" + ... + + +def is_stream_class_type(typ: type) -> TypeGuard[type[Stream[object]] | type[AsyncStream[object]]]: + """TypeGuard for determining whether or not the given type is a subclass of `Stream` / `AsyncStream`""" + origin = get_origin(typ) or typ + return inspect.isclass(origin) and issubclass(origin, (Stream, AsyncStream)) + + +def extract_stream_chunk_type( + stream_cls: type, + *, + failure_message: str | None = None, +) -> type: + """Given a type like `Stream[T]`, returns the generic type variable `T`. + + This also handles the case where a concrete subclass is given, e.g. + ```py + class MyStream(Stream[bytes]): + ... + + extract_stream_chunk_type(MyStream) -> bytes + ``` + """ + from ._base_client import Stream, AsyncStream + + return extract_type_var_from_base( + stream_cls, + index=0, + generic_bases=cast("tuple[type, ...]", (Stream, AsyncStream)), + failure_message=failure_message, + ) diff --git a/src/gcore/_types.py b/src/gcore/_types.py new file mode 100644 index 00000000..bbc3b7c8 --- /dev/null +++ b/src/gcore/_types.py @@ -0,0 +1,270 @@ +from __future__ import annotations + +from os import PathLike +from typing import ( + IO, + TYPE_CHECKING, + Any, + Dict, + List, + Type, + Tuple, + Union, + Mapping, + TypeVar, + Callable, + Iterable, + Iterator, + Optional, + Sequence, + AsyncIterable, +) +from typing_extensions import ( + Set, + Literal, + Protocol, + TypeAlias, + TypedDict, + SupportsIndex, + overload, + override, + runtime_checkable, +) + +import httpx +import pydantic +from httpx import URL, Proxy, Timeout, Response, BaseTransport, AsyncBaseTransport + +if TYPE_CHECKING: + from ._models import BaseModel + from ._response import APIResponse, AsyncAPIResponse + +Transport = BaseTransport +AsyncTransport = AsyncBaseTransport +Query = Mapping[str, object] +Body = object +AnyMapping = Mapping[str, object] +ModelT = TypeVar("ModelT", bound=pydantic.BaseModel) +_T = TypeVar("_T") + + +# Approximates httpx internal ProxiesTypes and RequestFiles types +# while adding support for `PathLike` instances +ProxiesDict = Dict["str | URL", Union[None, str, URL, Proxy]] +ProxiesTypes = Union[str, Proxy, ProxiesDict] +if TYPE_CHECKING: + Base64FileInput = Union[IO[bytes], PathLike[str]] + FileContent = Union[IO[bytes], bytes, PathLike[str]] +else: + Base64FileInput = Union[IO[bytes], PathLike] + FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8. + + +# Used for sending raw binary data / streaming data in request bodies +# e.g. for file uploads without multipart encoding +BinaryTypes = Union[bytes, bytearray, IO[bytes], Iterable[bytes]] +AsyncBinaryTypes = Union[bytes, bytearray, IO[bytes], AsyncIterable[bytes]] + +FileTypes = Union[ + # file (or bytes) + FileContent, + # (filename, file (or bytes)) + Tuple[Optional[str], FileContent], + # (filename, file (or bytes), content_type) + Tuple[Optional[str], FileContent, Optional[str]], + # (filename, file (or bytes), content_type, headers) + Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], +] +RequestFiles = Union[Mapping[str, FileTypes], Sequence[Tuple[str, FileTypes]]] + +# duplicate of the above but without our custom file support +HttpxFileContent = Union[IO[bytes], bytes] +HttpxFileTypes = Union[ + # file (or bytes) + HttpxFileContent, + # (filename, file (or bytes)) + Tuple[Optional[str], HttpxFileContent], + # (filename, file (or bytes), content_type) + Tuple[Optional[str], HttpxFileContent, Optional[str]], + # (filename, file (or bytes), content_type, headers) + Tuple[Optional[str], HttpxFileContent, Optional[str], Mapping[str, str]], +] +HttpxRequestFiles = Union[Mapping[str, HttpxFileTypes], Sequence[Tuple[str, HttpxFileTypes]]] + +# Workaround to support (cast_to: Type[ResponseT]) -> ResponseT +# where ResponseT includes `None`. In order to support directly +# passing `None`, overloads would have to be defined for every +# method that uses `ResponseT` which would lead to an unacceptable +# amount of code duplication and make it unreadable. See _base_client.py +# for example usage. +# +# This unfortunately means that you will either have +# to import this type and pass it explicitly: +# +# from gcore import NoneType +# client.get('/foo', cast_to=NoneType) +# +# or build it yourself: +# +# client.get('/foo', cast_to=type(None)) +if TYPE_CHECKING: + NoneType: Type[None] +else: + NoneType = type(None) + + +class RequestOptions(TypedDict, total=False): + headers: Headers + max_retries: int + timeout: float | Timeout | None + params: Query + extra_json: AnyMapping + idempotency_key: str + follow_redirects: bool + + +# Sentinel class used until PEP 0661 is accepted +class NotGiven: + """ + For parameters with a meaningful None value, we need to distinguish between + the user explicitly passing None, and the user not passing the parameter at + all. + + User code shouldn't need to use not_given directly. + + For example: + + ```py + def create(timeout: Timeout | None | NotGiven = not_given): ... + + + create(timeout=1) # 1s timeout + create(timeout=None) # No timeout + create() # Default timeout behavior + ``` + """ + + def __bool__(self) -> Literal[False]: + return False + + @override + def __repr__(self) -> str: + return "NOT_GIVEN" + + +not_given = NotGiven() +# for backwards compatibility: +NOT_GIVEN = NotGiven() + + +class Omit: + """ + To explicitly omit something from being sent in a request, use `omit`. + + ```py + # as the default `Content-Type` header is `application/json` that will be sent + client.post("/upload/files", files={"file": b"my raw file content"}) + + # you can't explicitly override the header as it has to be dynamically generated + # to look something like: 'multipart/form-data; boundary=0d8382fcf5f8c3be01ca2e11002d2983' + client.post(..., headers={"Content-Type": "multipart/form-data"}) + + # instead you can remove the default `application/json` header by passing omit + client.post(..., headers={"Content-Type": omit}) + ``` + """ + + def __bool__(self) -> Literal[False]: + return False + + +omit = Omit() + + +@runtime_checkable +class ModelBuilderProtocol(Protocol): + @classmethod + def build( + cls: type[_T], + *, + response: Response, + data: object, + ) -> _T: ... + + +Headers = Mapping[str, Union[str, Omit]] + + +class HeadersLikeProtocol(Protocol): + def get(self, __key: str) -> str | None: ... + + +HeadersLike = Union[Headers, HeadersLikeProtocol] + +ResponseT = TypeVar( + "ResponseT", + bound=Union[ + object, + str, + None, + "BaseModel", + List[Any], + Dict[str, Any], + Response, + ModelBuilderProtocol, + "APIResponse[Any]", + "AsyncAPIResponse[Any]", + ], +) + +StrBytesIntFloat = Union[str, bytes, int, float] + +# Note: copied from Pydantic +# https://github.com/pydantic/pydantic/blob/6f31f8f68ef011f84357330186f603ff295312fd/pydantic/main.py#L79 +IncEx: TypeAlias = Union[Set[int], Set[str], Mapping[int, Union["IncEx", bool]], Mapping[str, Union["IncEx", bool]]] + +PostParser = Callable[[Any], Any] + + +@runtime_checkable +class InheritsGeneric(Protocol): + """Represents a type that has inherited from `Generic` + + The `__orig_bases__` property can be used to determine the resolved + type variable for a given base class. + """ + + __orig_bases__: tuple[_GenericAlias] + + +class _GenericAlias(Protocol): + __origin__: type[object] + + +class HttpxSendArgs(TypedDict, total=False): + auth: httpx.Auth + follow_redirects: bool + + +_T_co = TypeVar("_T_co", covariant=True) + + +if TYPE_CHECKING: + # This works because str.__contains__ does not accept object (either in typeshed or at runtime) + # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 + # + # Note: index() and count() methods are intentionally omitted to allow pyright to properly + # infer TypedDict types when dict literals are used in lists assigned to SequenceNotStr. + class SequenceNotStr(Protocol[_T_co]): + @overload + def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... + @overload + def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... + def __contains__(self, value: object, /) -> bool: ... + def __len__(self) -> int: ... + def __iter__(self) -> Iterator[_T_co]: ... + def __reversed__(self) -> Iterator[_T_co]: ... +else: + # just point this to a normal `Sequence` at runtime to avoid having to special case + # deserializing our custom sequence type + SequenceNotStr = Sequence diff --git a/src/gcore/_utils/__init__.py b/src/gcore/_utils/__init__.py new file mode 100644 index 00000000..dc64e29a --- /dev/null +++ b/src/gcore/_utils/__init__.py @@ -0,0 +1,64 @@ +from ._sync import asyncify as asyncify +from ._proxy import LazyProxy as LazyProxy +from ._utils import ( + flatten as flatten, + is_dict as is_dict, + is_list as is_list, + is_given as is_given, + is_tuple as is_tuple, + json_safe as json_safe, + lru_cache as lru_cache, + is_mapping as is_mapping, + is_tuple_t as is_tuple_t, + is_iterable as is_iterable, + is_sequence as is_sequence, + coerce_float as coerce_float, + is_mapping_t as is_mapping_t, + removeprefix as removeprefix, + removesuffix as removesuffix, + extract_files as extract_files, + is_sequence_t as is_sequence_t, + required_args as required_args, + coerce_boolean as coerce_boolean, + coerce_integer as coerce_integer, + file_from_path as file_from_path, + strip_not_given as strip_not_given, + deepcopy_minimal as deepcopy_minimal, + get_async_library as get_async_library, + maybe_coerce_float as maybe_coerce_float, + get_required_header as get_required_header, + maybe_coerce_boolean as maybe_coerce_boolean, + maybe_coerce_integer as maybe_coerce_integer, +) +from ._compat import ( + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + is_typeddict as is_typeddict, + is_literal_type as is_literal_type, +) +from ._typing import ( + is_list_type as is_list_type, + is_union_type as is_union_type, + extract_type_arg as extract_type_arg, + is_iterable_type as is_iterable_type, + is_required_type as is_required_type, + is_sequence_type as is_sequence_type, + is_annotated_type as is_annotated_type, + is_type_alias_type as is_type_alias_type, + strip_annotated_type as strip_annotated_type, + extract_type_var_from_base as extract_type_var_from_base, +) +from ._streams import consume_sync_iterator as consume_sync_iterator, consume_async_iterator as consume_async_iterator +from ._transform import ( + PropertyInfo as PropertyInfo, + transform as transform, + async_transform as async_transform, + maybe_transform as maybe_transform, + async_maybe_transform as async_maybe_transform, +) +from ._reflection import ( + function_has_argument as function_has_argument, + assert_signatures_in_sync as assert_signatures_in_sync, +) +from ._datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime diff --git a/src/gcore/_utils/_compat.py b/src/gcore/_utils/_compat.py new file mode 100644 index 00000000..2c70b299 --- /dev/null +++ b/src/gcore/_utils/_compat.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +import sys +import typing_extensions +from typing import Any, Type, Union, Literal, Optional +from datetime import date, datetime +from typing_extensions import get_args as _get_args, get_origin as _get_origin + +from .._types import StrBytesIntFloat +from ._datetime_parse import parse_date as _parse_date, parse_datetime as _parse_datetime + +_LITERAL_TYPES = {Literal, typing_extensions.Literal} + + +def get_args(tp: type[Any]) -> tuple[Any, ...]: + return _get_args(tp) + + +def get_origin(tp: type[Any]) -> type[Any] | None: + return _get_origin(tp) + + +def is_union(tp: Optional[Type[Any]]) -> bool: + if sys.version_info < (3, 10): + return tp is Union # type: ignore[comparison-overlap] + else: + import types + + return tp is Union or tp is types.UnionType # type: ignore[comparison-overlap] + + +def is_typeddict(tp: Type[Any]) -> bool: + return typing_extensions.is_typeddict(tp) + + +def is_literal_type(tp: Type[Any]) -> bool: + return get_origin(tp) in _LITERAL_TYPES + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + return _parse_date(value) + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + return _parse_datetime(value) diff --git a/src/gcore/_utils/_datetime_parse.py b/src/gcore/_utils/_datetime_parse.py new file mode 100644 index 00000000..7cb9d9e6 --- /dev/null +++ b/src/gcore/_utils/_datetime_parse.py @@ -0,0 +1,136 @@ +""" +This file contains code from https://github.com/pydantic/pydantic/blob/main/pydantic/v1/datetime_parse.py +without the Pydantic v1 specific errors. +""" + +from __future__ import annotations + +import re +from typing import Dict, Union, Optional +from datetime import date, datetime, timezone, timedelta + +from .._types import StrBytesIntFloat + +date_expr = r"(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})" +time_expr = ( + r"(?P\d{1,2}):(?P\d{1,2})" + r"(?::(?P\d{1,2})(?:\.(?P\d{1,6})\d{0,6})?)?" + r"(?PZ|[+-]\d{2}(?::?\d{2})?)?$" +) + +date_re = re.compile(f"{date_expr}$") +datetime_re = re.compile(f"{date_expr}[T ]{time_expr}") + + +EPOCH = datetime(1970, 1, 1) +# if greater than this, the number is in ms, if less than or equal it's in seconds +# (in seconds this is 11th October 2603, in ms it's 20th August 1970) +MS_WATERSHED = int(2e10) +# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9 +MAX_NUMBER = int(3e20) + + +def _get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]: + if isinstance(value, (int, float)): + return value + try: + return float(value) + except ValueError: + return None + except TypeError: + raise TypeError(f"invalid type; expected {native_expected_type}, string, bytes, int or float") from None + + +def _from_unix_seconds(seconds: Union[int, float]) -> datetime: + if seconds > MAX_NUMBER: + return datetime.max + elif seconds < -MAX_NUMBER: + return datetime.min + + while abs(seconds) > MS_WATERSHED: + seconds /= 1000 + dt = EPOCH + timedelta(seconds=seconds) + return dt.replace(tzinfo=timezone.utc) + + +def _parse_timezone(value: Optional[str]) -> Union[None, int, timezone]: + if value == "Z": + return timezone.utc + elif value is not None: + offset_mins = int(value[-2:]) if len(value) > 3 else 0 + offset = 60 * int(value[1:3]) + offset_mins + if value[0] == "-": + offset = -offset + return timezone(timedelta(minutes=offset)) + else: + return None + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + """ + Parse a datetime/int/float/string and return a datetime.datetime. + + This function supports time zone offsets. When the input contains one, + the output uses a timezone with a fixed offset from UTC. + + Raise ValueError if the input is well formatted but not a valid datetime. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, datetime): + return value + + number = _get_numeric(value, "datetime") + if number is not None: + return _from_unix_seconds(number) + + if isinstance(value, bytes): + value = value.decode() + + assert not isinstance(value, (float, int)) + + match = datetime_re.match(value) + if match is None: + raise ValueError("invalid datetime format") + + kw = match.groupdict() + if kw["microsecond"]: + kw["microsecond"] = kw["microsecond"].ljust(6, "0") + + tzinfo = _parse_timezone(kw.pop("tzinfo")) + kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} + kw_["tzinfo"] = tzinfo + + return datetime(**kw_) # type: ignore + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + """ + Parse a date/int/float/string and return a datetime.date. + + Raise ValueError if the input is well formatted but not a valid date. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, date): + if isinstance(value, datetime): + return value.date() + else: + return value + + number = _get_numeric(value, "date") + if number is not None: + return _from_unix_seconds(number).date() + + if isinstance(value, bytes): + value = value.decode() + + assert not isinstance(value, (float, int)) + match = date_re.match(value) + if match is None: + raise ValueError("invalid date format") + + kw = {k: int(v) for k, v in match.groupdict().items()} + + try: + return date(**kw) + except ValueError: + raise ValueError("invalid date format") from None diff --git a/src/gcore/_utils/_json.py b/src/gcore/_utils/_json.py new file mode 100644 index 00000000..60584214 --- /dev/null +++ b/src/gcore/_utils/_json.py @@ -0,0 +1,35 @@ +import json +from typing import Any +from datetime import datetime +from typing_extensions import override + +import pydantic + +from .._compat import model_dump + + +def openapi_dumps(obj: Any) -> bytes: + """ + Serialize an object to UTF-8 encoded JSON bytes. + + Extends the standard json.dumps with support for additional types + commonly used in the SDK, such as `datetime`, `pydantic.BaseModel`, etc. + """ + return json.dumps( + obj, + cls=_CustomEncoder, + # Uses the same defaults as httpx's JSON serialization + ensure_ascii=False, + separators=(",", ":"), + allow_nan=False, + ).encode() + + +class _CustomEncoder(json.JSONEncoder): + @override + def default(self, o: Any) -> Any: + if isinstance(o, datetime): + return o.isoformat() + if isinstance(o, pydantic.BaseModel): + return model_dump(o, exclude_unset=True, mode="json", by_alias=True) + return super().default(o) diff --git a/src/gcore/_utils/_logs.py b/src/gcore/_utils/_logs.py new file mode 100644 index 00000000..9a53146b --- /dev/null +++ b/src/gcore/_utils/_logs.py @@ -0,0 +1,25 @@ +import os +import logging + +logger: logging.Logger = logging.getLogger("gcore") +httpx_logger: logging.Logger = logging.getLogger("httpx") + + +def _basic_config() -> None: + # e.g. [2023-10-05 14:12:26 - gcore._base_client:818 - DEBUG] HTTP Request: POST http://127.0.0.1:4010/foo/bar "200 OK" + logging.basicConfig( + format="[%(asctime)s - %(name)s:%(lineno)d - %(levelname)s] %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + + +def setup_logging() -> None: + env = os.environ.get("GCORE_LOG") + if env == "debug": + _basic_config() + logger.setLevel(logging.DEBUG) + httpx_logger.setLevel(logging.DEBUG) + elif env == "info": + _basic_config() + logger.setLevel(logging.INFO) + httpx_logger.setLevel(logging.INFO) diff --git a/src/gcore/_utils/_proxy.py b/src/gcore/_utils/_proxy.py new file mode 100644 index 00000000..0f239a33 --- /dev/null +++ b/src/gcore/_utils/_proxy.py @@ -0,0 +1,65 @@ +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import Generic, TypeVar, Iterable, cast +from typing_extensions import override + +T = TypeVar("T") + + +class LazyProxy(Generic[T], ABC): + """Implements data methods to pretend that an instance is another instance. + + This includes forwarding attribute access and other methods. + """ + + # Note: we have to special case proxies that themselves return proxies + # to support using a proxy as a catch-all for any random access, e.g. `proxy.foo.bar.baz` + + def __getattr__(self, attr: str) -> object: + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return proxied # pyright: ignore + return getattr(proxied, attr) + + @override + def __repr__(self) -> str: + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return proxied.__class__.__name__ + return repr(self.__get_proxied__()) + + @override + def __str__(self) -> str: + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return proxied.__class__.__name__ + return str(proxied) + + @override + def __dir__(self) -> Iterable[str]: + proxied = self.__get_proxied__() + if isinstance(proxied, LazyProxy): + return [] + return proxied.__dir__() + + @property # type: ignore + @override + def __class__(self) -> type: # pyright: ignore + try: + proxied = self.__get_proxied__() + except Exception: + return type(self) + if issubclass(type(proxied), LazyProxy): + return type(proxied) + return proxied.__class__ + + def __get_proxied__(self) -> T: + return self.__load__() + + def __as_proxied__(self) -> T: + """Helper method that returns the current proxy, typed as the loaded object""" + return cast(T, self) + + @abstractmethod + def __load__(self) -> T: ... diff --git a/src/gcore/_utils/_reflection.py b/src/gcore/_utils/_reflection.py new file mode 100644 index 00000000..89aa712a --- /dev/null +++ b/src/gcore/_utils/_reflection.py @@ -0,0 +1,42 @@ +from __future__ import annotations + +import inspect +from typing import Any, Callable + + +def function_has_argument(func: Callable[..., Any], arg_name: str) -> bool: + """Returns whether or not the given function has a specific parameter""" + sig = inspect.signature(func) + return arg_name in sig.parameters + + +def assert_signatures_in_sync( + source_func: Callable[..., Any], + check_func: Callable[..., Any], + *, + exclude_params: set[str] = set(), +) -> None: + """Ensure that the signature of the second function matches the first.""" + + check_sig = inspect.signature(check_func) + source_sig = inspect.signature(source_func) + + errors: list[str] = [] + + for name, source_param in source_sig.parameters.items(): + if name in exclude_params: + continue + + custom_param = check_sig.parameters.get(name) + if not custom_param: + errors.append(f"the `{name}` param is missing") + continue + + if custom_param.annotation != source_param.annotation: + errors.append( + f"types for the `{name}` param are do not match; source={repr(source_param.annotation)} checking={repr(custom_param.annotation)}" + ) + continue + + if errors: + raise AssertionError(f"{len(errors)} errors encountered when comparing signatures:\n\n" + "\n\n".join(errors)) diff --git a/src/gcore/_utils/_resources_proxy.py b/src/gcore/_utils/_resources_proxy.py new file mode 100644 index 00000000..22dfdbd2 --- /dev/null +++ b/src/gcore/_utils/_resources_proxy.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import Any +from typing_extensions import override + +from ._proxy import LazyProxy + + +class ResourcesProxy(LazyProxy[Any]): + """A proxy for the `gcore.resources` module. + + This is used so that we can lazily import `gcore.resources` only when + needed *and* so that users can just import `gcore` and reference `gcore.resources` + """ + + @override + def __load__(self) -> Any: + import importlib + + mod = importlib.import_module("gcore.resources") + return mod + + +resources = ResourcesProxy().__as_proxied__() diff --git a/src/gcore/_utils/_streams.py b/src/gcore/_utils/_streams.py new file mode 100644 index 00000000..f4a0208f --- /dev/null +++ b/src/gcore/_utils/_streams.py @@ -0,0 +1,12 @@ +from typing import Any +from typing_extensions import Iterator, AsyncIterator + + +def consume_sync_iterator(iterator: Iterator[Any]) -> None: + for _ in iterator: + ... + + +async def consume_async_iterator(iterator: AsyncIterator[Any]) -> None: + async for _ in iterator: + ... diff --git a/src/gcore/_utils/_sync.py b/src/gcore/_utils/_sync.py new file mode 100644 index 00000000..f6027c18 --- /dev/null +++ b/src/gcore/_utils/_sync.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import asyncio +import functools +from typing import TypeVar, Callable, Awaitable +from typing_extensions import ParamSpec + +import anyio +import sniffio +import anyio.to_thread + +T_Retval = TypeVar("T_Retval") +T_ParamSpec = ParamSpec("T_ParamSpec") + + +async def to_thread( + func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs +) -> T_Retval: + if sniffio.current_async_library() == "asyncio": + return await asyncio.to_thread(func, *args, **kwargs) + + return await anyio.to_thread.run_sync( + functools.partial(func, *args, **kwargs), + ) + + +# inspired by `asyncer`, https://github.com/tiangolo/asyncer +def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: + """ + Take a blocking function and create an async one that receives the same + positional and keyword arguments. + + Usage: + + ```python + def blocking_func(arg1, arg2, kwarg1=None): + # blocking code + return result + + + result = asyncify(blocking_function)(arg1, arg2, kwarg1=value1) + ``` + + ## Arguments + + `function`: a blocking regular callable (e.g. a function) + + ## Return + + An async function that takes the same positional and keyword arguments as the + original one, that when called runs the same original function in a thread worker + and returns the result. + """ + + async def wrapper(*args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs) -> T_Retval: + return await to_thread(function, *args, **kwargs) + + return wrapper diff --git a/src/gcore/_utils/_transform.py b/src/gcore/_utils/_transform.py new file mode 100644 index 00000000..52075492 --- /dev/null +++ b/src/gcore/_utils/_transform.py @@ -0,0 +1,457 @@ +from __future__ import annotations + +import io +import base64 +import pathlib +from typing import Any, Mapping, TypeVar, cast +from datetime import date, datetime +from typing_extensions import Literal, get_args, override, get_type_hints as _get_type_hints + +import anyio +import pydantic + +from ._utils import ( + is_list, + is_given, + lru_cache, + is_mapping, + is_iterable, + is_sequence, +) +from .._files import is_base64_file_input +from ._compat import get_origin, is_typeddict +from ._typing import ( + is_list_type, + is_union_type, + extract_type_arg, + is_iterable_type, + is_required_type, + is_sequence_type, + is_annotated_type, + strip_annotated_type, +) + +_T = TypeVar("_T") + + +# TODO: support for drilling globals() and locals() +# TODO: ensure works correctly with forward references in all cases + + +PropertyFormat = Literal["iso8601", "base64", "custom"] + + +class PropertyInfo: + """Metadata class to be used in Annotated types to provide information about a given type. + + For example: + + class MyParams(TypedDict): + account_holder_name: Annotated[str, PropertyInfo(alias='accountHolderName')] + + This means that {'account_holder_name': 'Robert'} will be transformed to {'accountHolderName': 'Robert'} before being sent to the API. + """ + + alias: str | None + format: PropertyFormat | None + format_template: str | None + discriminator: str | None + + def __init__( + self, + *, + alias: str | None = None, + format: PropertyFormat | None = None, + format_template: str | None = None, + discriminator: str | None = None, + ) -> None: + self.alias = alias + self.format = format + self.format_template = format_template + self.discriminator = discriminator + + @override + def __repr__(self) -> str: + return f"{self.__class__.__name__}(alias='{self.alias}', format={self.format}, format_template='{self.format_template}', discriminator='{self.discriminator}')" + + +def maybe_transform( + data: object, + expected_type: object, +) -> Any | None: + """Wrapper over `transform()` that allows `None` to be passed. + + See `transform()` for more details. + """ + if data is None: + return None + return transform(data, expected_type) + + +# Wrapper over _transform_recursive providing fake types +def transform( + data: _T, + expected_type: object, +) -> _T: + """Transform dictionaries based off of type information from the given type, for example: + + ```py + class Params(TypedDict, total=False): + card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]] + + + transformed = transform({"card_id": ""}, Params) + # {'cardID': ''} + ``` + + Any keys / data that does not have type information given will be included as is. + + It should be noted that the transformations that this function does are not represented in the type system. + """ + transformed = _transform_recursive(data, annotation=cast(type, expected_type)) + return cast(_T, transformed) + + +@lru_cache(maxsize=8096) +def _get_annotated_type(type_: type) -> type | None: + """If the given type is an `Annotated` type then it is returned, if not `None` is returned. + + This also unwraps the type when applicable, e.g. `Required[Annotated[T, ...]]` + """ + if is_required_type(type_): + # Unwrap `Required[Annotated[T, ...]]` to `Annotated[T, ...]` + type_ = get_args(type_)[0] + + if is_annotated_type(type_): + return type_ + + return None + + +def _maybe_transform_key(key: str, type_: type) -> str: + """Transform the given `data` based on the annotations provided in `type_`. + + Note: this function only looks at `Annotated` types that contain `PropertyInfo` metadata. + """ + annotated_type = _get_annotated_type(type_) + if annotated_type is None: + # no `Annotated` definition for this type, no transformation needed + return key + + # ignore the first argument as it is the actual type + annotations = get_args(annotated_type)[1:] + for annotation in annotations: + if isinstance(annotation, PropertyInfo) and annotation.alias is not None: + return annotation.alias + + return key + + +def _no_transform_needed(annotation: type) -> bool: + return annotation == float or annotation == int + + +def _transform_recursive( + data: object, + *, + annotation: type, + inner_type: type | None = None, +) -> object: + """Transform the given data against the expected type. + + Args: + annotation: The direct type annotation given to the particular piece of data. + This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc + + inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type + is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in + the list can be transformed using the metadata from the container type. + + Defaults to the same value as the `annotation` argument. + """ + from .._compat import model_dump + + if inner_type is None: + inner_type = annotation + + stripped_type = strip_annotated_type(inner_type) + origin = get_origin(stripped_type) or stripped_type + if is_typeddict(stripped_type) and is_mapping(data): + return _transform_typeddict(data, stripped_type) + + if origin == dict and is_mapping(data): + items_type = get_args(stripped_type)[1] + return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} + + if ( + # List[T] + (is_list_type(stripped_type) and is_list(data)) + # Iterable[T] + or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) + ): + # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually + # intended as an iterable, so we don't transform it. + if isinstance(data, dict): + return cast(object, data) + + inner_type = extract_type_arg(stripped_type, 0) + if _no_transform_needed(inner_type): + # for some types there is no need to transform anything, so we can get a small + # perf boost from skipping that work. + # + # but we still need to convert to a list to ensure the data is json-serializable + if is_list(data): + return data + return list(data) + + return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] + + if is_union_type(stripped_type): + # For union types we run the transformation against all subtypes to ensure that everything is transformed. + # + # TODO: there may be edge cases where the same normalized field name will transform to two different names + # in different subtypes. + for subtype in get_args(stripped_type): + data = _transform_recursive(data, annotation=annotation, inner_type=subtype) + return data + + if isinstance(data, pydantic.BaseModel): + return model_dump(data, exclude_unset=True, mode="json") + + annotated_type = _get_annotated_type(annotation) + if annotated_type is None: + return data + + # ignore the first argument as it is the actual type + annotations = get_args(annotated_type)[1:] + for annotation in annotations: + if isinstance(annotation, PropertyInfo) and annotation.format is not None: + return _format_data(data, annotation.format, annotation.format_template) + + return data + + +def _format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object: + if isinstance(data, (date, datetime)): + if format_ == "iso8601": + return data.isoformat() + + if format_ == "custom" and format_template is not None: + return data.strftime(format_template) + + if format_ == "base64" and is_base64_file_input(data): + binary: str | bytes | None = None + + if isinstance(data, pathlib.Path): + binary = data.read_bytes() + elif isinstance(data, io.IOBase): + binary = data.read() + + if isinstance(binary, str): # type: ignore[unreachable] + binary = binary.encode() + + if not isinstance(binary, bytes): + raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}") + + return base64.b64encode(binary).decode("ascii") + + return data + + +def _transform_typeddict( + data: Mapping[str, object], + expected_type: type, +) -> Mapping[str, object]: + result: dict[str, object] = {} + annotations = get_type_hints(expected_type, include_extras=True) + for key, value in data.items(): + if not is_given(value): + # we don't need to include omitted values here as they'll + # be stripped out before the request is sent anyway + continue + + type_ = annotations.get(key) + if type_ is None: + # we do not have a type annotation for this field, leave it as is + result[key] = value + else: + result[_maybe_transform_key(key, type_)] = _transform_recursive(value, annotation=type_) + return result + + +async def async_maybe_transform( + data: object, + expected_type: object, +) -> Any | None: + """Wrapper over `async_transform()` that allows `None` to be passed. + + See `async_transform()` for more details. + """ + if data is None: + return None + return await async_transform(data, expected_type) + + +async def async_transform( + data: _T, + expected_type: object, +) -> _T: + """Transform dictionaries based off of type information from the given type, for example: + + ```py + class Params(TypedDict, total=False): + card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]] + + + transformed = transform({"card_id": ""}, Params) + # {'cardID': ''} + ``` + + Any keys / data that does not have type information given will be included as is. + + It should be noted that the transformations that this function does are not represented in the type system. + """ + transformed = await _async_transform_recursive(data, annotation=cast(type, expected_type)) + return cast(_T, transformed) + + +async def _async_transform_recursive( + data: object, + *, + annotation: type, + inner_type: type | None = None, +) -> object: + """Transform the given data against the expected type. + + Args: + annotation: The direct type annotation given to the particular piece of data. + This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc + + inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type + is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in + the list can be transformed using the metadata from the container type. + + Defaults to the same value as the `annotation` argument. + """ + from .._compat import model_dump + + if inner_type is None: + inner_type = annotation + + stripped_type = strip_annotated_type(inner_type) + origin = get_origin(stripped_type) or stripped_type + if is_typeddict(stripped_type) and is_mapping(data): + return await _async_transform_typeddict(data, stripped_type) + + if origin == dict and is_mapping(data): + items_type = get_args(stripped_type)[1] + return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} + + if ( + # List[T] + (is_list_type(stripped_type) and is_list(data)) + # Iterable[T] + or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) + ): + # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually + # intended as an iterable, so we don't transform it. + if isinstance(data, dict): + return cast(object, data) + + inner_type = extract_type_arg(stripped_type, 0) + if _no_transform_needed(inner_type): + # for some types there is no need to transform anything, so we can get a small + # perf boost from skipping that work. + # + # but we still need to convert to a list to ensure the data is json-serializable + if is_list(data): + return data + return list(data) + + return [await _async_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] + + if is_union_type(stripped_type): + # For union types we run the transformation against all subtypes to ensure that everything is transformed. + # + # TODO: there may be edge cases where the same normalized field name will transform to two different names + # in different subtypes. + for subtype in get_args(stripped_type): + data = await _async_transform_recursive(data, annotation=annotation, inner_type=subtype) + return data + + if isinstance(data, pydantic.BaseModel): + return model_dump(data, exclude_unset=True, mode="json") + + annotated_type = _get_annotated_type(annotation) + if annotated_type is None: + return data + + # ignore the first argument as it is the actual type + annotations = get_args(annotated_type)[1:] + for annotation in annotations: + if isinstance(annotation, PropertyInfo) and annotation.format is not None: + return await _async_format_data(data, annotation.format, annotation.format_template) + + return data + + +async def _async_format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object: + if isinstance(data, (date, datetime)): + if format_ == "iso8601": + return data.isoformat() + + if format_ == "custom" and format_template is not None: + return data.strftime(format_template) + + if format_ == "base64" and is_base64_file_input(data): + binary: str | bytes | None = None + + if isinstance(data, pathlib.Path): + binary = await anyio.Path(data).read_bytes() + elif isinstance(data, io.IOBase): + binary = data.read() + + if isinstance(binary, str): # type: ignore[unreachable] + binary = binary.encode() + + if not isinstance(binary, bytes): + raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}") + + return base64.b64encode(binary).decode("ascii") + + return data + + +async def _async_transform_typeddict( + data: Mapping[str, object], + expected_type: type, +) -> Mapping[str, object]: + result: dict[str, object] = {} + annotations = get_type_hints(expected_type, include_extras=True) + for key, value in data.items(): + if not is_given(value): + # we don't need to include omitted values here as they'll + # be stripped out before the request is sent anyway + continue + + type_ = annotations.get(key) + if type_ is None: + # we do not have a type annotation for this field, leave it as is + result[key] = value + else: + result[_maybe_transform_key(key, type_)] = await _async_transform_recursive(value, annotation=type_) + return result + + +@lru_cache(maxsize=8096) +def get_type_hints( + obj: Any, + globalns: dict[str, Any] | None = None, + localns: Mapping[str, Any] | None = None, + include_extras: bool = False, +) -> dict[str, Any]: + return _get_type_hints(obj, globalns=globalns, localns=localns, include_extras=include_extras) diff --git a/src/gcore/_utils/_typing.py b/src/gcore/_utils/_typing.py new file mode 100644 index 00000000..193109f3 --- /dev/null +++ b/src/gcore/_utils/_typing.py @@ -0,0 +1,156 @@ +from __future__ import annotations + +import sys +import typing +import typing_extensions +from typing import Any, TypeVar, Iterable, cast +from collections import abc as _c_abc +from typing_extensions import ( + TypeIs, + Required, + Annotated, + get_args, + get_origin, +) + +from ._utils import lru_cache +from .._types import InheritsGeneric +from ._compat import is_union as _is_union + + +def is_annotated_type(typ: type) -> bool: + return get_origin(typ) == Annotated + + +def is_list_type(typ: type) -> bool: + return (get_origin(typ) or typ) == list + + +def is_sequence_type(typ: type) -> bool: + origin = get_origin(typ) or typ + return origin == typing_extensions.Sequence or origin == typing.Sequence or origin == _c_abc.Sequence + + +def is_iterable_type(typ: type) -> bool: + """If the given type is `typing.Iterable[T]`""" + origin = get_origin(typ) or typ + return origin == Iterable or origin == _c_abc.Iterable + + +def is_union_type(typ: type) -> bool: + return _is_union(get_origin(typ)) + + +def is_required_type(typ: type) -> bool: + return get_origin(typ) == Required + + +def is_typevar(typ: type) -> bool: + # type ignore is required because type checkers + # think this expression will always return False + return type(typ) == TypeVar # type: ignore + + +_TYPE_ALIAS_TYPES: tuple[type[typing_extensions.TypeAliasType], ...] = (typing_extensions.TypeAliasType,) +if sys.version_info >= (3, 12): + _TYPE_ALIAS_TYPES = (*_TYPE_ALIAS_TYPES, typing.TypeAliasType) + + +def is_type_alias_type(tp: Any, /) -> TypeIs[typing_extensions.TypeAliasType]: + """Return whether the provided argument is an instance of `TypeAliasType`. + + ```python + type Int = int + is_type_alias_type(Int) + # > True + Str = TypeAliasType("Str", str) + is_type_alias_type(Str) + # > True + ``` + """ + return isinstance(tp, _TYPE_ALIAS_TYPES) + + +# Extracts T from Annotated[T, ...] or from Required[Annotated[T, ...]] +@lru_cache(maxsize=8096) +def strip_annotated_type(typ: type) -> type: + if is_required_type(typ) or is_annotated_type(typ): + return strip_annotated_type(cast(type, get_args(typ)[0])) + + return typ + + +def extract_type_arg(typ: type, index: int) -> type: + args = get_args(typ) + try: + return cast(type, args[index]) + except IndexError as err: + raise RuntimeError(f"Expected type {typ} to have a type argument at index {index} but it did not") from err + + +def extract_type_var_from_base( + typ: type, + *, + generic_bases: tuple[type, ...], + index: int, + failure_message: str | None = None, +) -> type: + """Given a type like `Foo[T]`, returns the generic type variable `T`. + + This also handles the case where a concrete subclass is given, e.g. + ```py + class MyResponse(Foo[bytes]): + ... + + extract_type_var(MyResponse, bases=(Foo,), index=0) -> bytes + ``` + + And where a generic subclass is given: + ```py + _T = TypeVar('_T') + class MyResponse(Foo[_T]): + ... + + extract_type_var(MyResponse[bytes], bases=(Foo,), index=0) -> bytes + ``` + """ + cls = cast(object, get_origin(typ) or typ) + if cls in generic_bases: # pyright: ignore[reportUnnecessaryContains] + # we're given the class directly + return extract_type_arg(typ, index) + + # if a subclass is given + # --- + # this is needed as __orig_bases__ is not present in the typeshed stubs + # because it is intended to be for internal use only, however there does + # not seem to be a way to resolve generic TypeVars for inherited subclasses + # without using it. + if isinstance(cls, InheritsGeneric): + target_base_class: Any | None = None + for base in cls.__orig_bases__: + if base.__origin__ in generic_bases: + target_base_class = base + break + + if target_base_class is None: + raise RuntimeError( + "Could not find the generic base class;\n" + "This should never happen;\n" + f"Does {cls} inherit from one of {generic_bases} ?" + ) + + extracted = extract_type_arg(target_base_class, index) + if is_typevar(extracted): + # If the extracted type argument is itself a type variable + # then that means the subclass itself is generic, so we have + # to resolve the type argument from the class itself, not + # the base class. + # + # Note: if there is more than 1 type argument, the subclass could + # change the ordering of the type arguments, this is not currently + # supported. + return extract_type_arg(typ, index) + + return extracted + + raise RuntimeError(failure_message or f"Could not resolve inner type variable at index {index} for {typ}") diff --git a/src/gcore/_utils/_utils.py b/src/gcore/_utils/_utils.py new file mode 100644 index 00000000..eec7f4a1 --- /dev/null +++ b/src/gcore/_utils/_utils.py @@ -0,0 +1,421 @@ +from __future__ import annotations + +import os +import re +import inspect +import functools +from typing import ( + Any, + Tuple, + Mapping, + TypeVar, + Callable, + Iterable, + Sequence, + cast, + overload, +) +from pathlib import Path +from datetime import date, datetime +from typing_extensions import TypeGuard + +import sniffio + +from .._types import Omit, NotGiven, FileTypes, HeadersLike + +_T = TypeVar("_T") +_TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) +_MappingT = TypeVar("_MappingT", bound=Mapping[str, object]) +_SequenceT = TypeVar("_SequenceT", bound=Sequence[object]) +CallableT = TypeVar("CallableT", bound=Callable[..., Any]) + + +def flatten(t: Iterable[Iterable[_T]]) -> list[_T]: + return [item for sublist in t for item in sublist] + + +def extract_files( + # TODO: this needs to take Dict but variance issues..... + # create protocol type ? + query: Mapping[str, object], + *, + paths: Sequence[Sequence[str]], +) -> list[tuple[str, FileTypes]]: + """Recursively extract files from the given dictionary based on specified paths. + + A path may look like this ['foo', 'files', '', 'data']. + + Note: this mutates the given dictionary. + """ + files: list[tuple[str, FileTypes]] = [] + for path in paths: + files.extend(_extract_items(query, path, index=0, flattened_key=None)) + return files + + +def _extract_items( + obj: object, + path: Sequence[str], + *, + index: int, + flattened_key: str | None, +) -> list[tuple[str, FileTypes]]: + try: + key = path[index] + except IndexError: + if not is_given(obj): + # no value was provided - we can safely ignore + return [] + + # cyclical import + from .._files import assert_is_file_content + + # We have exhausted the path, return the entry we found. + assert flattened_key is not None + + if is_list(obj): + files: list[tuple[str, FileTypes]] = [] + for entry in obj: + assert_is_file_content(entry, key=flattened_key + "[]" if flattened_key else "") + files.append((flattened_key + "[]", cast(FileTypes, entry))) + return files + + assert_is_file_content(obj, key=flattened_key) + return [(flattened_key, cast(FileTypes, obj))] + + index += 1 + if is_dict(obj): + try: + # We are at the last entry in the path so we must remove the field + if (len(path)) == index: + item = obj.pop(key) + else: + item = obj[key] + except KeyError: + # Key was not present in the dictionary, this is not indicative of an error + # as the given path may not point to a required field. We also do not want + # to enforce required fields as the API may differ from the spec in some cases. + return [] + if flattened_key is None: + flattened_key = key + else: + flattened_key += f"[{key}]" + return _extract_items( + item, + path, + index=index, + flattened_key=flattened_key, + ) + elif is_list(obj): + if key != "": + return [] + + return flatten( + [ + _extract_items( + item, + path, + index=index, + flattened_key=flattened_key + "[]" if flattened_key is not None else "[]", + ) + for item in obj + ] + ) + + # Something unexpected was passed, just ignore it. + return [] + + +def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]: + return not isinstance(obj, NotGiven) and not isinstance(obj, Omit) + + +# Type safe methods for narrowing types with TypeVars. +# The default narrowing for isinstance(obj, dict) is dict[unknown, unknown], +# however this cause Pyright to rightfully report errors. As we know we don't +# care about the contained types we can safely use `object` in its place. +# +# There are two separate functions defined, `is_*` and `is_*_t` for different use cases. +# `is_*` is for when you're dealing with an unknown input +# `is_*_t` is for when you're narrowing a known union type to a specific subset + + +def is_tuple(obj: object) -> TypeGuard[tuple[object, ...]]: + return isinstance(obj, tuple) + + +def is_tuple_t(obj: _TupleT | object) -> TypeGuard[_TupleT]: + return isinstance(obj, tuple) + + +def is_sequence(obj: object) -> TypeGuard[Sequence[object]]: + return isinstance(obj, Sequence) + + +def is_sequence_t(obj: _SequenceT | object) -> TypeGuard[_SequenceT]: + return isinstance(obj, Sequence) + + +def is_mapping(obj: object) -> TypeGuard[Mapping[str, object]]: + return isinstance(obj, Mapping) + + +def is_mapping_t(obj: _MappingT | object) -> TypeGuard[_MappingT]: + return isinstance(obj, Mapping) + + +def is_dict(obj: object) -> TypeGuard[dict[object, object]]: + return isinstance(obj, dict) + + +def is_list(obj: object) -> TypeGuard[list[object]]: + return isinstance(obj, list) + + +def is_iterable(obj: object) -> TypeGuard[Iterable[object]]: + return isinstance(obj, Iterable) + + +def deepcopy_minimal(item: _T) -> _T: + """Minimal reimplementation of copy.deepcopy() that will only copy certain object types: + + - mappings, e.g. `dict` + - list + + This is done for performance reasons. + """ + if is_mapping(item): + return cast(_T, {k: deepcopy_minimal(v) for k, v in item.items()}) + if is_list(item): + return cast(_T, [deepcopy_minimal(entry) for entry in item]) + return item + + +# copied from https://github.com/Rapptz/RoboDanny +def human_join(seq: Sequence[str], *, delim: str = ", ", final: str = "or") -> str: + size = len(seq) + if size == 0: + return "" + + if size == 1: + return seq[0] + + if size == 2: + return f"{seq[0]} {final} {seq[1]}" + + return delim.join(seq[:-1]) + f" {final} {seq[-1]}" + + +def quote(string: str) -> str: + """Add single quotation marks around the given string. Does *not* do any escaping.""" + return f"'{string}'" + + +def required_args(*variants: Sequence[str]) -> Callable[[CallableT], CallableT]: + """Decorator to enforce a given set of arguments or variants of arguments are passed to the decorated function. + + Useful for enforcing runtime validation of overloaded functions. + + Example usage: + ```py + @overload + def foo(*, a: str) -> str: ... + + + @overload + def foo(*, b: bool) -> str: ... + + + # This enforces the same constraints that a static type checker would + # i.e. that either a or b must be passed to the function + @required_args(["a"], ["b"]) + def foo(*, a: str | None = None, b: bool | None = None) -> str: ... + ``` + """ + + def inner(func: CallableT) -> CallableT: + params = inspect.signature(func).parameters + positional = [ + name + for name, param in params.items() + if param.kind + in { + param.POSITIONAL_ONLY, + param.POSITIONAL_OR_KEYWORD, + } + ] + + @functools.wraps(func) + def wrapper(*args: object, **kwargs: object) -> object: + given_params: set[str] = set() + for i, _ in enumerate(args): + try: + given_params.add(positional[i]) + except IndexError: + raise TypeError( + f"{func.__name__}() takes {len(positional)} argument(s) but {len(args)} were given" + ) from None + + for key in kwargs.keys(): + given_params.add(key) + + for variant in variants: + matches = all((param in given_params for param in variant)) + if matches: + break + else: # no break + if len(variants) > 1: + variations = human_join( + ["(" + human_join([quote(arg) for arg in variant], final="and") + ")" for variant in variants] + ) + msg = f"Missing required arguments; Expected either {variations} arguments to be given" + else: + assert len(variants) > 0 + + # TODO: this error message is not deterministic + missing = list(set(variants[0]) - given_params) + if len(missing) > 1: + msg = f"Missing required arguments: {human_join([quote(arg) for arg in missing])}" + else: + msg = f"Missing required argument: {quote(missing[0])}" + raise TypeError(msg) + return func(*args, **kwargs) + + return wrapper # type: ignore + + return inner + + +_K = TypeVar("_K") +_V = TypeVar("_V") + + +@overload +def strip_not_given(obj: None) -> None: ... + + +@overload +def strip_not_given(obj: Mapping[_K, _V | NotGiven]) -> dict[_K, _V]: ... + + +@overload +def strip_not_given(obj: object) -> object: ... + + +def strip_not_given(obj: object | None) -> object: + """Remove all top-level keys where their values are instances of `NotGiven`""" + if obj is None: + return None + + if not is_mapping(obj): + return obj + + return {key: value for key, value in obj.items() if not isinstance(value, NotGiven)} + + +def coerce_integer(val: str) -> int: + return int(val, base=10) + + +def coerce_float(val: str) -> float: + return float(val) + + +def coerce_boolean(val: str) -> bool: + return val == "true" or val == "1" or val == "on" + + +def maybe_coerce_integer(val: str | None) -> int | None: + if val is None: + return None + return coerce_integer(val) + + +def maybe_coerce_float(val: str | None) -> float | None: + if val is None: + return None + return coerce_float(val) + + +def maybe_coerce_boolean(val: str | None) -> bool | None: + if val is None: + return None + return coerce_boolean(val) + + +def removeprefix(string: str, prefix: str) -> str: + """Remove a prefix from a string. + + Backport of `str.removeprefix` for Python < 3.9 + """ + if string.startswith(prefix): + return string[len(prefix) :] + return string + + +def removesuffix(string: str, suffix: str) -> str: + """Remove a suffix from a string. + + Backport of `str.removesuffix` for Python < 3.9 + """ + if string.endswith(suffix): + return string[: -len(suffix)] + return string + + +def file_from_path(path: str) -> FileTypes: + contents = Path(path).read_bytes() + file_name = os.path.basename(path) + return (file_name, contents) + + +def get_required_header(headers: HeadersLike, header: str) -> str: + lower_header = header.lower() + if is_mapping_t(headers): + # mypy doesn't understand the type narrowing here + for k, v in headers.items(): # type: ignore + if k.lower() == lower_header and isinstance(v, str): + return v + + # to deal with the case where the header looks like Stainless-Event-Id + intercaps_header = re.sub(r"([^\w])(\w)", lambda pat: pat.group(1) + pat.group(2).upper(), header.capitalize()) + + for normalized_header in [header, lower_header, header.upper(), intercaps_header]: + value = headers.get(normalized_header) + if value: + return value + + raise ValueError(f"Could not find {header} header") + + +def get_async_library() -> str: + try: + return sniffio.current_async_library() + except Exception: + return "false" + + +def lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]: + """A version of functools.lru_cache that retains the type signature + for the wrapped function arguments. + """ + wrapper = functools.lru_cache( # noqa: TID251 + maxsize=maxsize, + ) + return cast(Any, wrapper) # type: ignore[no-any-return] + + +def json_safe(data: object) -> object: + """Translates a mapping / sequence recursively in the same fashion + as `pydantic` v2's `model_dump(mode="json")`. + """ + if is_mapping(data): + return {json_safe(key): json_safe(value) for key, value in data.items()} + + if is_iterable(data) and not isinstance(data, (str, bytes, bytearray)): + return [json_safe(item) for item in data] + + if isinstance(data, (datetime, date)): + return data.isoformat() + + return data diff --git a/src/gcore/_version.py b/src/gcore/_version.py new file mode 100644 index 00000000..f2c32ca0 --- /dev/null +++ b/src/gcore/_version.py @@ -0,0 +1,4 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +__title__ = "gcore" +__version__ = "0.33.0" # x-release-please-version diff --git a/src/gcore/lib/.keep b/src/gcore/lib/.keep new file mode 100644 index 00000000..5e2c99fd --- /dev/null +++ b/src/gcore/lib/.keep @@ -0,0 +1,4 @@ +File generated from our OpenAPI spec by Stainless. + +This directory can be used to store custom files to expand the SDK. +It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. \ No newline at end of file diff --git a/src/gcore/pagination.py b/src/gcore/pagination.py new file mode 100644 index 00000000..872117cd --- /dev/null +++ b/src/gcore/pagination.py @@ -0,0 +1,496 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Any, List, Type, Generic, Mapping, TypeVar, Optional, cast +from typing_extensions import override + +from httpx import Response + +from ._utils import is_mapping +from ._models import BaseModel +from ._base_client import BasePage, PageInfo, BaseSyncPage, BaseAsyncPage + +__all__ = [ + "SyncOffsetPage", + "AsyncOffsetPage", + "SyncOffsetPageFastedgeApps", + "AsyncOffsetPageFastedgeApps", + "SyncOffsetPageFastedgeTemplates", + "AsyncOffsetPageFastedgeTemplates", + "SyncOffsetPageFastedgeAppLogs", + "AsyncOffsetPageFastedgeAppLogs", + "SyncPageStreamingAI", + "AsyncPageStreamingAI", + "SyncPageStreaming", + "AsyncPageStreaming", + "SyncOffsetPageCDN", + "AsyncOffsetPageCDN", + "OffsetPageCDNLogsMeta", + "SyncOffsetPageCDNLogs", + "AsyncOffsetPageCDNLogs", +] + +_BaseModelT = TypeVar("_BaseModelT", bound=BaseModel) + +_T = TypeVar("_T") + + +class SyncOffsetPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + results: List[_T] + count: Optional[int] = None + + @override + def _get_page_items(self) -> List[_T]: + results = self.results + if not results: + return [] + return results + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + count = self.count + if count is None: + return None + + if current_count < count: + return PageInfo(params={"offset": current_count}) + + return None + + +class AsyncOffsetPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + results: List[_T] + count: Optional[int] = None + + @override + def _get_page_items(self) -> List[_T]: + results = self.results + if not results: + return [] + return results + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + count = self.count + if count is None: + return None + + if current_count < count: + return PageInfo(params={"offset": current_count}) + + return None + + +class SyncOffsetPageFastedgeApps(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + apps: List[_T] + count: Optional[int] = None + + @override + def _get_page_items(self) -> List[_T]: + apps = self.apps + if not apps: + return [] + return apps + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + count = self.count + if count is None: + return None + + if current_count < count: + return PageInfo(params={"offset": current_count}) + + return None + + +class AsyncOffsetPageFastedgeApps(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + apps: List[_T] + count: Optional[int] = None + + @override + def _get_page_items(self) -> List[_T]: + apps = self.apps + if not apps: + return [] + return apps + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + count = self.count + if count is None: + return None + + if current_count < count: + return PageInfo(params={"offset": current_count}) + + return None + + +class SyncOffsetPageFastedgeTemplates(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + templates: List[_T] + count: Optional[int] = None + + @override + def _get_page_items(self) -> List[_T]: + templates = self.templates + if not templates: + return [] + return templates + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + count = self.count + if count is None: + return None + + if current_count < count: + return PageInfo(params={"offset": current_count}) + + return None + + +class AsyncOffsetPageFastedgeTemplates(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + templates: List[_T] + count: Optional[int] = None + + @override + def _get_page_items(self) -> List[_T]: + templates = self.templates + if not templates: + return [] + return templates + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + count = self.count + if count is None: + return None + + if current_count < count: + return PageInfo(params={"offset": current_count}) + + return None + + +class SyncOffsetPageFastedgeAppLogs(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + logs: List[_T] + total_count: Optional[int] = None + + @override + def _get_page_items(self) -> List[_T]: + logs = self.logs + if not logs: + return [] + return logs + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + total_count = self.total_count + if total_count is None: + return None + + if current_count < total_count: + return PageInfo(params={"offset": current_count}) + + return None + + +class AsyncOffsetPageFastedgeAppLogs(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + logs: List[_T] + total_count: Optional[int] = None + + @override + def _get_page_items(self) -> List[_T]: + logs = self.logs + if not logs: + return [] + return logs + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + total_count = self.total_count + if total_count is None: + return None + + if current_count < total_count: + return PageInfo(params={"offset": current_count}) + + return None + + +class SyncPageStreamingAI(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + results: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + results = self.results + if not results: + return [] + return results + + @override + def next_page_info(self) -> Optional[PageInfo]: + last_page = cast("int | None", self._options.params.get("page")) or 1 + + return PageInfo(params={"page": last_page + 1}) + + +class AsyncPageStreamingAI(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + results: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + results = self.results + if not results: + return [] + return results + + @override + def next_page_info(self) -> Optional[PageInfo]: + last_page = cast("int | None", self._options.params.get("page")) or 1 + + return PageInfo(params={"page": last_page + 1}) + + +class SyncPageStreaming(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + items: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + items = self.items + if not items: + return [] + return items + + @override + def next_page_info(self) -> None: + """ + This page represents a response that isn't actually paginated at the API level + so there will never be a next page. + """ + return None + + @classmethod + def build(cls: Type[_BaseModelT], *, response: Response, data: object) -> _BaseModelT: # noqa: ARG003 + return cls.construct( + None, + **{ + **(cast(Mapping[str, Any], data) if is_mapping(data) else {"items": data}), + }, + ) + + +class AsyncPageStreaming(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + items: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + items = self.items + if not items: + return [] + return items + + @override + def next_page_info(self) -> None: + """ + This page represents a response that isn't actually paginated at the API level + so there will never be a next page. + """ + return None + + @classmethod + def build(cls: Type[_BaseModelT], *, response: Response, data: object) -> _BaseModelT: # noqa: ARG003 + return cls.construct( + None, + **{ + **(cast(Mapping[str, Any], data) if is_mapping(data) else {"items": data}), + }, + ) + + +class SyncOffsetPageCDN(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + items: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + items = self.items + if not items: + return [] + return items + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + return PageInfo(params={"offset": current_count}) + + @classmethod + def build(cls: Type[_BaseModelT], *, response: Response, data: object) -> _BaseModelT: # noqa: ARG003 + return cls.construct( + None, + **{ + **(cast(Mapping[str, Any], data) if is_mapping(data) else {"items": data}), + }, + ) + + +class AsyncOffsetPageCDN(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + items: List[_T] + + @override + def _get_page_items(self) -> List[_T]: + items = self.items + if not items: + return [] + return items + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + return PageInfo(params={"offset": current_count}) + + @classmethod + def build(cls: Type[_BaseModelT], *, response: Response, data: object) -> _BaseModelT: # noqa: ARG003 + return cls.construct( + None, + **{ + **(cast(Mapping[str, Any], data) if is_mapping(data) else {"items": data}), + }, + ) + + +class OffsetPageCDNLogsMeta(BaseModel): + count: Optional[int] = None + + +class SyncOffsetPageCDNLogs(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + data: List[_T] + meta: Optional[OffsetPageCDNLogsMeta] = None + + @override + def _get_page_items(self) -> List[_T]: + data = self.data + if not data: + return [] + return data + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + count = None + if self.meta is not None: + if self.meta.count is not None: + count = self.meta.count + if count is None: + return None + + if current_count < count: + return PageInfo(params={"offset": current_count}) + + return None + + +class AsyncOffsetPageCDNLogs(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + data: List[_T] + meta: Optional[OffsetPageCDNLogsMeta] = None + + @override + def _get_page_items(self) -> List[_T]: + data = self.data + if not data: + return [] + return data + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + count = None + if self.meta is not None: + if self.meta.count is not None: + count = self.meta.count + if count is None: + return None + + if current_count < count: + return PageInfo(params={"offset": current_count}) + + return None diff --git a/src/gcore/py.typed b/src/gcore/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/src/gcore/resources/__init__.py b/src/gcore/resources/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/src/gcore/resources/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/src/gcore/resources/cdn/__init__.py b/src/gcore/resources/cdn/__init__.py new file mode 100644 index 00000000..869fc050 --- /dev/null +++ b/src/gcore/resources/cdn/__init__.py @@ -0,0 +1,201 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .cdn import ( + CDNResource, + AsyncCDNResource, + CDNResourceWithRawResponse, + AsyncCDNResourceWithRawResponse, + CDNResourceWithStreamingResponse, + AsyncCDNResourceWithStreamingResponse, +) +from .logs import ( + LogsResource, + AsyncLogsResource, + LogsResourceWithRawResponse, + AsyncLogsResourceWithRawResponse, + LogsResourceWithStreamingResponse, + AsyncLogsResourceWithStreamingResponse, +) +from .metrics import ( + MetricsResource, + AsyncMetricsResource, + MetricsResourceWithRawResponse, + AsyncMetricsResourceWithRawResponse, + MetricsResourceWithStreamingResponse, + AsyncMetricsResourceWithStreamingResponse, +) +from .shields import ( + ShieldsResource, + AsyncShieldsResource, + ShieldsResourceWithRawResponse, + AsyncShieldsResourceWithRawResponse, + ShieldsResourceWithStreamingResponse, + AsyncShieldsResourceWithStreamingResponse, +) +from .ip_ranges import ( + IPRangesResource, + AsyncIPRangesResource, + IPRangesResourceWithRawResponse, + AsyncIPRangesResourceWithRawResponse, + IPRangesResourceWithStreamingResponse, + AsyncIPRangesResourceWithStreamingResponse, +) +from .audit_logs import ( + AuditLogsResource, + AsyncAuditLogsResource, + AuditLogsResourceWithRawResponse, + AsyncAuditLogsResourceWithRawResponse, + AuditLogsResourceWithStreamingResponse, + AsyncAuditLogsResourceWithStreamingResponse, +) +from .statistics import ( + StatisticsResource, + AsyncStatisticsResource, + StatisticsResourceWithRawResponse, + AsyncStatisticsResourceWithRawResponse, + StatisticsResourceWithStreamingResponse, + AsyncStatisticsResourceWithStreamingResponse, +) +from .certificates import ( + CertificatesResource, + AsyncCertificatesResource, + CertificatesResourceWithRawResponse, + AsyncCertificatesResourceWithRawResponse, + CertificatesResourceWithStreamingResponse, + AsyncCertificatesResourceWithStreamingResponse, +) +from .cdn_resources import ( + CDNResourcesResource, + AsyncCDNResourcesResource, + CDNResourcesResourceWithRawResponse, + AsyncCDNResourcesResourceWithRawResponse, + CDNResourcesResourceWithStreamingResponse, + AsyncCDNResourcesResourceWithStreamingResponse, +) +from .logs_uploader import ( + LogsUploaderResource, + AsyncLogsUploaderResource, + LogsUploaderResourceWithRawResponse, + AsyncLogsUploaderResourceWithRawResponse, + LogsUploaderResourceWithStreamingResponse, + AsyncLogsUploaderResourceWithStreamingResponse, +) +from .origin_groups import ( + OriginGroupsResource, + AsyncOriginGroupsResource, + OriginGroupsResourceWithRawResponse, + AsyncOriginGroupsResourceWithRawResponse, + OriginGroupsResourceWithStreamingResponse, + AsyncOriginGroupsResourceWithStreamingResponse, +) +from .rule_templates import ( + RuleTemplatesResource, + AsyncRuleTemplatesResource, + RuleTemplatesResourceWithRawResponse, + AsyncRuleTemplatesResourceWithRawResponse, + RuleTemplatesResourceWithStreamingResponse, + AsyncRuleTemplatesResourceWithStreamingResponse, +) +from .network_capacity import ( + NetworkCapacityResource, + AsyncNetworkCapacityResource, + NetworkCapacityResourceWithRawResponse, + AsyncNetworkCapacityResourceWithRawResponse, + NetworkCapacityResourceWithStreamingResponse, + AsyncNetworkCapacityResourceWithStreamingResponse, +) +from .trusted_ca_certificates import ( + TrustedCaCertificatesResource, + AsyncTrustedCaCertificatesResource, + TrustedCaCertificatesResourceWithRawResponse, + AsyncTrustedCaCertificatesResourceWithRawResponse, + TrustedCaCertificatesResourceWithStreamingResponse, + AsyncTrustedCaCertificatesResourceWithStreamingResponse, +) + +__all__ = [ + "CDNResourcesResource", + "AsyncCDNResourcesResource", + "CDNResourcesResourceWithRawResponse", + "AsyncCDNResourcesResourceWithRawResponse", + "CDNResourcesResourceWithStreamingResponse", + "AsyncCDNResourcesResourceWithStreamingResponse", + "ShieldsResource", + "AsyncShieldsResource", + "ShieldsResourceWithRawResponse", + "AsyncShieldsResourceWithRawResponse", + "ShieldsResourceWithStreamingResponse", + "AsyncShieldsResourceWithStreamingResponse", + "OriginGroupsResource", + "AsyncOriginGroupsResource", + "OriginGroupsResourceWithRawResponse", + "AsyncOriginGroupsResourceWithRawResponse", + "OriginGroupsResourceWithStreamingResponse", + "AsyncOriginGroupsResourceWithStreamingResponse", + "RuleTemplatesResource", + "AsyncRuleTemplatesResource", + "RuleTemplatesResourceWithRawResponse", + "AsyncRuleTemplatesResourceWithRawResponse", + "RuleTemplatesResourceWithStreamingResponse", + "AsyncRuleTemplatesResourceWithStreamingResponse", + "CertificatesResource", + "AsyncCertificatesResource", + "CertificatesResourceWithRawResponse", + "AsyncCertificatesResourceWithRawResponse", + "CertificatesResourceWithStreamingResponse", + "AsyncCertificatesResourceWithStreamingResponse", + "TrustedCaCertificatesResource", + "AsyncTrustedCaCertificatesResource", + "TrustedCaCertificatesResourceWithRawResponse", + "AsyncTrustedCaCertificatesResourceWithRawResponse", + "TrustedCaCertificatesResourceWithStreamingResponse", + "AsyncTrustedCaCertificatesResourceWithStreamingResponse", + "AuditLogsResource", + "AsyncAuditLogsResource", + "AuditLogsResourceWithRawResponse", + "AsyncAuditLogsResourceWithRawResponse", + "AuditLogsResourceWithStreamingResponse", + "AsyncAuditLogsResourceWithStreamingResponse", + "LogsResource", + "AsyncLogsResource", + "LogsResourceWithRawResponse", + "AsyncLogsResourceWithRawResponse", + "LogsResourceWithStreamingResponse", + "AsyncLogsResourceWithStreamingResponse", + "LogsUploaderResource", + "AsyncLogsUploaderResource", + "LogsUploaderResourceWithRawResponse", + "AsyncLogsUploaderResourceWithRawResponse", + "LogsUploaderResourceWithStreamingResponse", + "AsyncLogsUploaderResourceWithStreamingResponse", + "StatisticsResource", + "AsyncStatisticsResource", + "StatisticsResourceWithRawResponse", + "AsyncStatisticsResourceWithRawResponse", + "StatisticsResourceWithStreamingResponse", + "AsyncStatisticsResourceWithStreamingResponse", + "NetworkCapacityResource", + "AsyncNetworkCapacityResource", + "NetworkCapacityResourceWithRawResponse", + "AsyncNetworkCapacityResourceWithRawResponse", + "NetworkCapacityResourceWithStreamingResponse", + "AsyncNetworkCapacityResourceWithStreamingResponse", + "MetricsResource", + "AsyncMetricsResource", + "MetricsResourceWithRawResponse", + "AsyncMetricsResourceWithRawResponse", + "MetricsResourceWithStreamingResponse", + "AsyncMetricsResourceWithStreamingResponse", + "IPRangesResource", + "AsyncIPRangesResource", + "IPRangesResourceWithRawResponse", + "AsyncIPRangesResourceWithRawResponse", + "IPRangesResourceWithStreamingResponse", + "AsyncIPRangesResourceWithStreamingResponse", + "CDNResource", + "AsyncCDNResource", + "CDNResourceWithRawResponse", + "AsyncCDNResourceWithRawResponse", + "CDNResourceWithStreamingResponse", + "AsyncCDNResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cdn/api.md b/src/gcore/resources/cdn/api.md new file mode 100644 index 00000000..70919175 --- /dev/null +++ b/src/gcore/resources/cdn/api.md @@ -0,0 +1,308 @@ +# CDN + +Types: + +```python +from gcore.types.cdn import ( + AlibabaRegions, + AwsRegions, + CDNAccount, + CDNAccountLimits, + CDNAvailableFeatures, + PurgeStatus, + CDNListPurgeStatusesResponse, +) +``` + +Methods: + +- client.cdn.get_account_limits() -> CDNAccountLimits +- client.cdn.get_account_overview() -> CDNAccount +- client.cdn.get_available_features() -> CDNAvailableFeatures +- client.cdn.list_alibaba_regions() -> AlibabaRegions +- client.cdn.list_aws_regions() -> AwsRegions +- client.cdn.list_purge_statuses(\*\*params) -> CDNListPurgeStatusesResponse +- client.cdn.update_account(\*\*params) -> CDNAccount + +## CDNResources + +Types: + +```python +from gcore.types.cdn import CDNResource, CDNResourceList +``` + +Methods: + +- client.cdn.cdn_resources.create(\*\*params) -> CDNResource +- client.cdn.cdn_resources.update(resource_id, \*\*params) -> CDNResource +- client.cdn.cdn_resources.list(\*\*params) -> CDNResourceList +- client.cdn.cdn_resources.delete(resource_id) -> None +- client.cdn.cdn_resources.get(resource_id) -> CDNResource +- client.cdn.cdn_resources.prefetch(resource_id, \*\*params) -> None +- client.cdn.cdn_resources.prevalidate_ssl_le_certificate(resource_id) -> None +- client.cdn.cdn_resources.purge(resource_id, \*\*params) -> None +- client.cdn.cdn_resources.replace(resource_id, \*\*params) -> CDNResource + +### Shield + +Types: + +```python +from gcore.types.cdn.cdn_resources import OriginShielding, OriginShieldingReplaced +``` + +Methods: + +- client.cdn.cdn_resources.shield.get(resource_id) -> OriginShielding +- client.cdn.cdn_resources.shield.replace(resource_id, \*\*params) -> object + +### Rules + +Types: + +```python +from gcore.types.cdn.cdn_resources import CDNResourceRule, RuleListResponse +``` + +Methods: + +- client.cdn.cdn_resources.rules.create(resource_id, \*\*params) -> CDNResourceRule +- client.cdn.cdn_resources.rules.update(rule_id, \*, resource_id, \*\*params) -> CDNResourceRule +- client.cdn.cdn_resources.rules.list(resource_id) -> RuleListResponse +- client.cdn.cdn_resources.rules.delete(rule_id, \*, resource_id) -> None +- client.cdn.cdn_resources.rules.get(rule_id, \*, resource_id) -> CDNResourceRule +- client.cdn.cdn_resources.rules.replace(rule_id, \*, resource_id, \*\*params) -> CDNResourceRule + +## Shields + +Types: + +```python +from gcore.types.cdn import ShieldListResponse +``` + +Methods: + +- client.cdn.shields.list() -> ShieldListResponse + +## OriginGroups + +Types: + +```python +from gcore.types.cdn import OriginGroups, OriginGroupsList +``` + +Methods: + +- client.cdn.origin_groups.create(\*\*params) -> OriginGroups +- client.cdn.origin_groups.update(origin_group_id, \*\*params) -> OriginGroups +- client.cdn.origin_groups.list(\*\*params) -> OriginGroupsList +- client.cdn.origin_groups.delete(origin_group_id) -> None +- client.cdn.origin_groups.get(origin_group_id) -> OriginGroups +- client.cdn.origin_groups.replace(origin_group_id, \*\*params) -> OriginGroups + +## RuleTemplates + +Types: + +```python +from gcore.types.cdn import RuleTemplate, RuleTemplateList +``` + +Methods: + +- client.cdn.rule_templates.create(\*\*params) -> RuleTemplate +- client.cdn.rule_templates.update(rule_template_id, \*\*params) -> RuleTemplate +- client.cdn.rule_templates.list() -> RuleTemplateList +- client.cdn.rule_templates.delete(rule_template_id) -> None +- client.cdn.rule_templates.get(rule_template_id) -> RuleTemplate +- client.cdn.rule_templates.replace(rule_template_id, \*\*params) -> RuleTemplate + +## Certificates + +Types: + +```python +from gcore.types.cdn import SslDetail, SslDetailList, SslRequestStatus +``` + +Methods: + +- client.cdn.certificates.create(\*\*params) -> None +- client.cdn.certificates.list(\*\*params) -> SslDetailList +- client.cdn.certificates.delete(ssl_id) -> None +- client.cdn.certificates.force_retry(cert_id) -> None +- client.cdn.certificates.get(ssl_id) -> SslDetail +- client.cdn.certificates.get_status(cert_id, \*\*params) -> SslRequestStatus +- client.cdn.certificates.renew(cert_id) -> None +- client.cdn.certificates.replace(ssl_id, \*\*params) -> SslDetail + +## TrustedCaCertificates + +Types: + +```python +from gcore.types.cdn import CaCertificate, CaCertificateList +``` + +Methods: + +- client.cdn.trusted_ca_certificates.create(\*\*params) -> CaCertificate +- client.cdn.trusted_ca_certificates.list(\*\*params) -> CaCertificateList +- client.cdn.trusted_ca_certificates.delete(id) -> None +- client.cdn.trusted_ca_certificates.get(id) -> CaCertificate +- client.cdn.trusted_ca_certificates.replace(id, \*\*params) -> CaCertificate + +## AuditLogs + +Types: + +```python +from gcore.types.cdn import CDNAuditLogEntry +``` + +Methods: + +- client.cdn.audit_logs.list(\*\*params) -> SyncOffsetPage[CDNAuditLogEntry] +- client.cdn.audit_logs.get(log_id) -> CDNAuditLogEntry + +## Logs + +Types: + +```python +from gcore.types.cdn import CDNLogEntry +``` + +Methods: + +- client.cdn.logs.list(\*\*params) -> SyncOffsetPageCDNLogs[Data] +- client.cdn.logs.download(\*\*params) -> BinaryAPIResponse + +## LogsUploader + +Types: + +```python +from gcore.types.cdn import LogsUploaderValidation +``` + +### Policies + +Types: + +```python +from gcore.types.cdn.logs_uploader import ( + LogsUploaderPolicy, + LogsUploaderPolicyList, + PolicyListFieldsResponse, +) +``` + +Methods: + +- client.cdn.logs_uploader.policies.create(\*\*params) -> LogsUploaderPolicy +- client.cdn.logs_uploader.policies.update(id, \*\*params) -> LogsUploaderPolicy +- client.cdn.logs_uploader.policies.list(\*\*params) -> LogsUploaderPolicyList +- client.cdn.logs_uploader.policies.delete(id) -> None +- client.cdn.logs_uploader.policies.get(id) -> LogsUploaderPolicy +- client.cdn.logs_uploader.policies.list_fields() -> PolicyListFieldsResponse +- client.cdn.logs_uploader.policies.replace(id, \*\*params) -> LogsUploaderPolicy + +### Targets + +Types: + +```python +from gcore.types.cdn.logs_uploader import LogsUploaderTarget, LogsUploaderTargetList +``` + +Methods: + +- client.cdn.logs_uploader.targets.create(\*\*params) -> LogsUploaderTarget +- client.cdn.logs_uploader.targets.update(id, \*\*params) -> LogsUploaderTarget +- client.cdn.logs_uploader.targets.list(\*\*params) -> LogsUploaderTargetList +- client.cdn.logs_uploader.targets.delete(id) -> None +- client.cdn.logs_uploader.targets.get(id) -> LogsUploaderTarget +- client.cdn.logs_uploader.targets.replace(id, \*\*params) -> LogsUploaderTarget +- client.cdn.logs_uploader.targets.validate(id) -> LogsUploaderValidation + +### Configs + +Types: + +```python +from gcore.types.cdn.logs_uploader import LogsUploaderConfig, LogsUploaderConfigList +``` + +Methods: + +- client.cdn.logs_uploader.configs.create(\*\*params) -> LogsUploaderConfig +- client.cdn.logs_uploader.configs.update(id, \*\*params) -> LogsUploaderConfig +- client.cdn.logs_uploader.configs.list(\*\*params) -> LogsUploaderConfigList +- client.cdn.logs_uploader.configs.delete(id) -> None +- client.cdn.logs_uploader.configs.get(id) -> LogsUploaderConfig +- client.cdn.logs_uploader.configs.replace(id, \*\*params) -> LogsUploaderConfig +- client.cdn.logs_uploader.configs.validate(id) -> LogsUploaderValidation + +## Statistics + +Types: + +```python +from gcore.types.cdn import ( + LogsAggregatedStats, + ResourceAggregatedStats, + ResourceUsageStats, + ShieldAggregatedStats, + UsageSeriesStats, +) +``` + +Methods: + +- client.cdn.statistics.get_logs_usage_aggregated(\*\*params) -> LogsAggregatedStats +- client.cdn.statistics.get_logs_usage_series(\*\*params) -> UsageSeriesStats +- client.cdn.statistics.get_resource_usage_aggregated(\*\*params) -> ResourceAggregatedStats +- client.cdn.statistics.get_resource_usage_series(\*\*params) -> ResourceUsageStats +- client.cdn.statistics.get_shield_usage_aggregated(\*\*params) -> ShieldAggregatedStats +- client.cdn.statistics.get_shield_usage_series(\*\*params) -> UsageSeriesStats + +## NetworkCapacity + +Types: + +```python +from gcore.types.cdn import NetworkCapacity +``` + +Methods: + +- client.cdn.network_capacity.list() -> NetworkCapacity + +## Metrics + +Types: + +```python +from gcore.types.cdn import CDNMetrics, CDNMetricsGroups, CDNMetricsValues +``` + +Methods: + +- client.cdn.metrics.list(\*\*params) -> CDNMetrics + +## IPRanges + +Types: + +```python +from gcore.types.cdn import PublicIPList, PublicNetworkList +``` + +Methods: + +- client.cdn.ip_ranges.list(\*\*params) -> PublicNetworkList +- client.cdn.ip_ranges.list_ips(\*\*params) -> PublicIPList diff --git a/src/gcore/resources/cdn/audit_logs.py b/src/gcore/resources/cdn/audit_logs.py new file mode 100644 index 00000000..e77a7315 --- /dev/null +++ b/src/gcore/resources/cdn/audit_logs.py @@ -0,0 +1,398 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cdn import audit_log_list_params +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.cdn.cdn_audit_log_entry import CDNAuditLogEntry + +__all__ = ["AuditLogsResource", "AsyncAuditLogsResource"] + + +class AuditLogsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> AuditLogsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AuditLogsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AuditLogsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AuditLogsResourceWithStreamingResponse(self) + + def list( + self, + *, + client_id: int | Omit = omit, + limit: int | Omit = omit, + max_requested_at: str | Omit = omit, + method: str | Omit = omit, + min_requested_at: str | Omit = omit, + offset: int | Omit = omit, + path: str | Omit = omit, + remote_ip_address: str | Omit = omit, + status_code: int | Omit = omit, + token_id: int | Omit = omit, + user_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[CDNAuditLogEntry]: + """ + Get information about all CDN activity logs records. + + Args: + client_id: Client ID. + + limit: Maximum number of items in response. + + max_requested_at: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + You can specify a date with a time separated by a space, or just a date. + + Examples: + + - &`max_requested_at`=2021-05-05 12:00:00 + - &`max_requested_at`=2021-05-05 + + method: HTTP method type of requests. + + Use upper case only. + + Example: + + - ?method=DELETE + + min_requested_at: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + You can specify a date with a time separated by a space, or just a date. + + Examples: + + - &`min_requested_at`=2021-05-05 12:00:00 + - &`min_requested_at`=2021-05-05 + + offset: Offset relative to the beginning of activity logs. + + path: Exact URL path. + + remote_ip_address: Exact IP address from which requests are sent. + + status_code: Status code returned in the response. + + Specify the first numbers of a status code to get requests for a group of status + codes. + + To filter the activity logs by 4xx codes, use: + + - &`status_code`=4 - + + token_id: Permanent API token ID. Requests made with this token should be displayed. + + user_id: User ID. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cdn/activity_log/requests", + page=SyncOffsetPage[CDNAuditLogEntry], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "client_id": client_id, + "limit": limit, + "max_requested_at": max_requested_at, + "method": method, + "min_requested_at": min_requested_at, + "offset": offset, + "path": path, + "remote_ip_address": remote_ip_address, + "status_code": status_code, + "token_id": token_id, + "user_id": user_id, + }, + audit_log_list_params.AuditLogListParams, + ), + ), + model=CDNAuditLogEntry, + ) + + def get( + self, + log_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNAuditLogEntry: + """ + Get information about CDN activity logs record. + + Args: + log_id: Activity logs record ID. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cdn/activity_log/requests/{log_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNAuditLogEntry, + ) + + +class AsyncAuditLogsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAuditLogsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncAuditLogsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAuditLogsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncAuditLogsResourceWithStreamingResponse(self) + + def list( + self, + *, + client_id: int | Omit = omit, + limit: int | Omit = omit, + max_requested_at: str | Omit = omit, + method: str | Omit = omit, + min_requested_at: str | Omit = omit, + offset: int | Omit = omit, + path: str | Omit = omit, + remote_ip_address: str | Omit = omit, + status_code: int | Omit = omit, + token_id: int | Omit = omit, + user_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[CDNAuditLogEntry, AsyncOffsetPage[CDNAuditLogEntry]]: + """ + Get information about all CDN activity logs records. + + Args: + client_id: Client ID. + + limit: Maximum number of items in response. + + max_requested_at: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + You can specify a date with a time separated by a space, or just a date. + + Examples: + + - &`max_requested_at`=2021-05-05 12:00:00 + - &`max_requested_at`=2021-05-05 + + method: HTTP method type of requests. + + Use upper case only. + + Example: + + - ?method=DELETE + + min_requested_at: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + You can specify a date with a time separated by a space, or just a date. + + Examples: + + - &`min_requested_at`=2021-05-05 12:00:00 + - &`min_requested_at`=2021-05-05 + + offset: Offset relative to the beginning of activity logs. + + path: Exact URL path. + + remote_ip_address: Exact IP address from which requests are sent. + + status_code: Status code returned in the response. + + Specify the first numbers of a status code to get requests for a group of status + codes. + + To filter the activity logs by 4xx codes, use: + + - &`status_code`=4 - + + token_id: Permanent API token ID. Requests made with this token should be displayed. + + user_id: User ID. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cdn/activity_log/requests", + page=AsyncOffsetPage[CDNAuditLogEntry], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "client_id": client_id, + "limit": limit, + "max_requested_at": max_requested_at, + "method": method, + "min_requested_at": min_requested_at, + "offset": offset, + "path": path, + "remote_ip_address": remote_ip_address, + "status_code": status_code, + "token_id": token_id, + "user_id": user_id, + }, + audit_log_list_params.AuditLogListParams, + ), + ), + model=CDNAuditLogEntry, + ) + + async def get( + self, + log_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNAuditLogEntry: + """ + Get information about CDN activity logs record. + + Args: + log_id: Activity logs record ID. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cdn/activity_log/requests/{log_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNAuditLogEntry, + ) + + +class AuditLogsResourceWithRawResponse: + def __init__(self, audit_logs: AuditLogsResource) -> None: + self._audit_logs = audit_logs + + self.list = to_raw_response_wrapper( + audit_logs.list, + ) + self.get = to_raw_response_wrapper( + audit_logs.get, + ) + + +class AsyncAuditLogsResourceWithRawResponse: + def __init__(self, audit_logs: AsyncAuditLogsResource) -> None: + self._audit_logs = audit_logs + + self.list = async_to_raw_response_wrapper( + audit_logs.list, + ) + self.get = async_to_raw_response_wrapper( + audit_logs.get, + ) + + +class AuditLogsResourceWithStreamingResponse: + def __init__(self, audit_logs: AuditLogsResource) -> None: + self._audit_logs = audit_logs + + self.list = to_streamed_response_wrapper( + audit_logs.list, + ) + self.get = to_streamed_response_wrapper( + audit_logs.get, + ) + + +class AsyncAuditLogsResourceWithStreamingResponse: + def __init__(self, audit_logs: AsyncAuditLogsResource) -> None: + self._audit_logs = audit_logs + + self.list = async_to_streamed_response_wrapper( + audit_logs.list, + ) + self.get = async_to_streamed_response_wrapper( + audit_logs.get, + ) diff --git a/src/gcore/resources/cdn/cdn.py b/src/gcore/resources/cdn/cdn.py new file mode 100644 index 00000000..771c3776 --- /dev/null +++ b/src/gcore/resources/cdn/cdn.py @@ -0,0 +1,1048 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .logs import ( + LogsResource, + AsyncLogsResource, + LogsResourceWithRawResponse, + AsyncLogsResourceWithRawResponse, + LogsResourceWithStreamingResponse, + AsyncLogsResourceWithStreamingResponse, +) +from .metrics import ( + MetricsResource, + AsyncMetricsResource, + MetricsResourceWithRawResponse, + AsyncMetricsResourceWithRawResponse, + MetricsResourceWithStreamingResponse, + AsyncMetricsResourceWithStreamingResponse, +) +from .shields import ( + ShieldsResource, + AsyncShieldsResource, + ShieldsResourceWithRawResponse, + AsyncShieldsResourceWithRawResponse, + ShieldsResourceWithStreamingResponse, + AsyncShieldsResourceWithStreamingResponse, +) +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from .ip_ranges import ( + IPRangesResource, + AsyncIPRangesResource, + IPRangesResourceWithRawResponse, + AsyncIPRangesResourceWithRawResponse, + IPRangesResourceWithStreamingResponse, + AsyncIPRangesResourceWithStreamingResponse, +) +from .audit_logs import ( + AuditLogsResource, + AsyncAuditLogsResource, + AuditLogsResourceWithRawResponse, + AsyncAuditLogsResourceWithRawResponse, + AuditLogsResourceWithStreamingResponse, + AsyncAuditLogsResourceWithStreamingResponse, +) +from .statistics import ( + StatisticsResource, + AsyncStatisticsResource, + StatisticsResourceWithRawResponse, + AsyncStatisticsResourceWithRawResponse, + StatisticsResourceWithStreamingResponse, + AsyncStatisticsResourceWithStreamingResponse, +) +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cdn import cdn_update_account_params, cdn_list_purge_statuses_params +from .certificates import ( + CertificatesResource, + AsyncCertificatesResource, + CertificatesResourceWithRawResponse, + AsyncCertificatesResourceWithRawResponse, + CertificatesResourceWithStreamingResponse, + AsyncCertificatesResourceWithStreamingResponse, +) +from .origin_groups import ( + OriginGroupsResource, + AsyncOriginGroupsResource, + OriginGroupsResourceWithRawResponse, + AsyncOriginGroupsResourceWithRawResponse, + OriginGroupsResourceWithStreamingResponse, + AsyncOriginGroupsResourceWithStreamingResponse, +) +from ..._base_client import make_request_options +from .rule_templates import ( + RuleTemplatesResource, + AsyncRuleTemplatesResource, + RuleTemplatesResourceWithRawResponse, + AsyncRuleTemplatesResourceWithRawResponse, + RuleTemplatesResourceWithStreamingResponse, + AsyncRuleTemplatesResourceWithStreamingResponse, +) +from .network_capacity import ( + NetworkCapacityResource, + AsyncNetworkCapacityResource, + NetworkCapacityResourceWithRawResponse, + AsyncNetworkCapacityResourceWithRawResponse, + NetworkCapacityResourceWithStreamingResponse, + AsyncNetworkCapacityResourceWithStreamingResponse, +) +from ...types.cdn.aws_regions import AwsRegions +from ...types.cdn.cdn_account import CDNAccount +from .trusted_ca_certificates import ( + TrustedCaCertificatesResource, + AsyncTrustedCaCertificatesResource, + TrustedCaCertificatesResourceWithRawResponse, + AsyncTrustedCaCertificatesResourceWithRawResponse, + TrustedCaCertificatesResourceWithStreamingResponse, + AsyncTrustedCaCertificatesResourceWithStreamingResponse, +) +from ...types.cdn.alibaba_regions import AlibabaRegions +from .cdn_resources.cdn_resources import ( + CDNResourcesResource, + AsyncCDNResourcesResource, + CDNResourcesResourceWithRawResponse, + AsyncCDNResourcesResourceWithRawResponse, + CDNResourcesResourceWithStreamingResponse, + AsyncCDNResourcesResourceWithStreamingResponse, +) +from .logs_uploader.logs_uploader import ( + LogsUploaderResource, + AsyncLogsUploaderResource, + LogsUploaderResourceWithRawResponse, + AsyncLogsUploaderResourceWithRawResponse, + LogsUploaderResourceWithStreamingResponse, + AsyncLogsUploaderResourceWithStreamingResponse, +) +from ...types.cdn.cdn_account_limits import CDNAccountLimits +from ...types.cdn.cdn_available_features import CDNAvailableFeatures +from ...types.cdn.cdn_list_purge_statuses_response import CDNListPurgeStatusesResponse + +__all__ = ["CDNResource", "AsyncCDNResource"] + + +class CDNResource(SyncAPIResource): + @cached_property + def cdn_resources(self) -> CDNResourcesResource: + return CDNResourcesResource(self._client) + + @cached_property + def shields(self) -> ShieldsResource: + return ShieldsResource(self._client) + + @cached_property + def origin_groups(self) -> OriginGroupsResource: + return OriginGroupsResource(self._client) + + @cached_property + def rule_templates(self) -> RuleTemplatesResource: + return RuleTemplatesResource(self._client) + + @cached_property + def certificates(self) -> CertificatesResource: + return CertificatesResource(self._client) + + @cached_property + def trusted_ca_certificates(self) -> TrustedCaCertificatesResource: + return TrustedCaCertificatesResource(self._client) + + @cached_property + def audit_logs(self) -> AuditLogsResource: + return AuditLogsResource(self._client) + + @cached_property + def logs(self) -> LogsResource: + return LogsResource(self._client) + + @cached_property + def logs_uploader(self) -> LogsUploaderResource: + return LogsUploaderResource(self._client) + + @cached_property + def statistics(self) -> StatisticsResource: + return StatisticsResource(self._client) + + @cached_property + def network_capacity(self) -> NetworkCapacityResource: + return NetworkCapacityResource(self._client) + + @cached_property + def metrics(self) -> MetricsResource: + return MetricsResource(self._client) + + @cached_property + def ip_ranges(self) -> IPRangesResource: + return IPRangesResource(self._client) + + @cached_property + def with_raw_response(self) -> CDNResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return CDNResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CDNResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return CDNResourceWithStreamingResponse(self) + + def get_account_limits( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNAccountLimits: + """Get information about CDN service limits.""" + return self._get( + "/cdn/clients/me/limits", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNAccountLimits, + ) + + def get_account_overview( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNAccount: + """Get information about CDN service.""" + return self._get( + "/cdn/clients/me", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNAccount, + ) + + def get_available_features( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNAvailableFeatures: + """Get information about available CDN features.""" + return self._get( + "/cdn/clients/me/features", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNAvailableFeatures, + ) + + def list_alibaba_regions( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AlibabaRegions: + """Get the list of Alibaba Cloud regions.""" + return self._get( + "/cdn/alibaba_regions", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AlibabaRegions, + ) + + def list_aws_regions( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AwsRegions: + """Get the list of Amazon AWS regions.""" + return self._get( + "/cdn/aws_regions", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AwsRegions, + ) + + def list_purge_statuses( + self, + *, + cname: str | Omit = omit, + from_created: str | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + purge_type: str | Omit = omit, + status: str | Omit = omit, + to_created: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNListPurgeStatusesResponse: + """ + Get purges history. + + Args: + cname: Purges associated with a specific resource CNAME. + + Example: + + - &cname=example.com + + from_created: Start date and time of the requested time period (ISO 8601/RFC 3339 format, + UTC.) + + Examples: + + - &`from_created`=2021-06-14T00:00:00Z + - &`from_created`=2021-06-14T00:00:00.000Z + + limit: Maximum number of purges in the response. + + offset: Number of purge requests in the response to skip starting from the beginning of + the requested period. + + purge_type: Purge requests with a certain purge type. + + Possible values: + + - **`purge_by_pattern`** - Purge by Pattern. + - **`purge_by_url`** - Purge by URL. + - **`purge_all`** - Purge All. + + status: Purge with a certain status. + + Possible values: + + - **In progress** + - **Successful** + - **Failed** + - **Status report disabled** + + to_created: End date and time of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + Examples: + + - &`to_created`=2021-06-15T00:00:00Z + - &`to_created`=2021-06-15T00:00:00.000Z + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/purge_statuses", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cname": cname, + "from_created": from_created, + "limit": limit, + "offset": offset, + "purge_type": purge_type, + "status": status, + "to_created": to_created, + }, + cdn_list_purge_statuses_params.CDNListPurgeStatusesParams, + ), + ), + cast_to=CDNListPurgeStatusesResponse, + ) + + def update_account( + self, + *, + utilization_level: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNAccount: + """ + Change information about CDN service. + + Args: + utilization_level: CDN traffic usage limit in gigabytes. + + When the limit is reached, we will send an email notification. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + "/cdn/clients/me", + body=maybe_transform( + {"utilization_level": utilization_level}, cdn_update_account_params.CDNUpdateAccountParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNAccount, + ) + + +class AsyncCDNResource(AsyncAPIResource): + @cached_property + def cdn_resources(self) -> AsyncCDNResourcesResource: + return AsyncCDNResourcesResource(self._client) + + @cached_property + def shields(self) -> AsyncShieldsResource: + return AsyncShieldsResource(self._client) + + @cached_property + def origin_groups(self) -> AsyncOriginGroupsResource: + return AsyncOriginGroupsResource(self._client) + + @cached_property + def rule_templates(self) -> AsyncRuleTemplatesResource: + return AsyncRuleTemplatesResource(self._client) + + @cached_property + def certificates(self) -> AsyncCertificatesResource: + return AsyncCertificatesResource(self._client) + + @cached_property + def trusted_ca_certificates(self) -> AsyncTrustedCaCertificatesResource: + return AsyncTrustedCaCertificatesResource(self._client) + + @cached_property + def audit_logs(self) -> AsyncAuditLogsResource: + return AsyncAuditLogsResource(self._client) + + @cached_property + def logs(self) -> AsyncLogsResource: + return AsyncLogsResource(self._client) + + @cached_property + def logs_uploader(self) -> AsyncLogsUploaderResource: + return AsyncLogsUploaderResource(self._client) + + @cached_property + def statistics(self) -> AsyncStatisticsResource: + return AsyncStatisticsResource(self._client) + + @cached_property + def network_capacity(self) -> AsyncNetworkCapacityResource: + return AsyncNetworkCapacityResource(self._client) + + @cached_property + def metrics(self) -> AsyncMetricsResource: + return AsyncMetricsResource(self._client) + + @cached_property + def ip_ranges(self) -> AsyncIPRangesResource: + return AsyncIPRangesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncCDNResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncCDNResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCDNResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncCDNResourceWithStreamingResponse(self) + + async def get_account_limits( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNAccountLimits: + """Get information about CDN service limits.""" + return await self._get( + "/cdn/clients/me/limits", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNAccountLimits, + ) + + async def get_account_overview( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNAccount: + """Get information about CDN service.""" + return await self._get( + "/cdn/clients/me", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNAccount, + ) + + async def get_available_features( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNAvailableFeatures: + """Get information about available CDN features.""" + return await self._get( + "/cdn/clients/me/features", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNAvailableFeatures, + ) + + async def list_alibaba_regions( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AlibabaRegions: + """Get the list of Alibaba Cloud regions.""" + return await self._get( + "/cdn/alibaba_regions", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AlibabaRegions, + ) + + async def list_aws_regions( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AwsRegions: + """Get the list of Amazon AWS regions.""" + return await self._get( + "/cdn/aws_regions", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AwsRegions, + ) + + async def list_purge_statuses( + self, + *, + cname: str | Omit = omit, + from_created: str | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + purge_type: str | Omit = omit, + status: str | Omit = omit, + to_created: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNListPurgeStatusesResponse: + """ + Get purges history. + + Args: + cname: Purges associated with a specific resource CNAME. + + Example: + + - &cname=example.com + + from_created: Start date and time of the requested time period (ISO 8601/RFC 3339 format, + UTC.) + + Examples: + + - &`from_created`=2021-06-14T00:00:00Z + - &`from_created`=2021-06-14T00:00:00.000Z + + limit: Maximum number of purges in the response. + + offset: Number of purge requests in the response to skip starting from the beginning of + the requested period. + + purge_type: Purge requests with a certain purge type. + + Possible values: + + - **`purge_by_pattern`** - Purge by Pattern. + - **`purge_by_url`** - Purge by URL. + - **`purge_all`** - Purge All. + + status: Purge with a certain status. + + Possible values: + + - **In progress** + - **Successful** + - **Failed** + - **Status report disabled** + + to_created: End date and time of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + Examples: + + - &`to_created`=2021-06-15T00:00:00Z + - &`to_created`=2021-06-15T00:00:00.000Z + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/purge_statuses", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "cname": cname, + "from_created": from_created, + "limit": limit, + "offset": offset, + "purge_type": purge_type, + "status": status, + "to_created": to_created, + }, + cdn_list_purge_statuses_params.CDNListPurgeStatusesParams, + ), + ), + cast_to=CDNListPurgeStatusesResponse, + ) + + async def update_account( + self, + *, + utilization_level: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNAccount: + """ + Change information about CDN service. + + Args: + utilization_level: CDN traffic usage limit in gigabytes. + + When the limit is reached, we will send an email notification. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + "/cdn/clients/me", + body=await async_maybe_transform( + {"utilization_level": utilization_level}, cdn_update_account_params.CDNUpdateAccountParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNAccount, + ) + + +class CDNResourceWithRawResponse: + def __init__(self, cdn: CDNResource) -> None: + self._cdn = cdn + + self.get_account_limits = to_raw_response_wrapper( + cdn.get_account_limits, + ) + self.get_account_overview = to_raw_response_wrapper( + cdn.get_account_overview, + ) + self.get_available_features = to_raw_response_wrapper( + cdn.get_available_features, + ) + self.list_alibaba_regions = to_raw_response_wrapper( + cdn.list_alibaba_regions, + ) + self.list_aws_regions = to_raw_response_wrapper( + cdn.list_aws_regions, + ) + self.list_purge_statuses = to_raw_response_wrapper( + cdn.list_purge_statuses, + ) + self.update_account = to_raw_response_wrapper( + cdn.update_account, + ) + + @cached_property + def cdn_resources(self) -> CDNResourcesResourceWithRawResponse: + return CDNResourcesResourceWithRawResponse(self._cdn.cdn_resources) + + @cached_property + def shields(self) -> ShieldsResourceWithRawResponse: + return ShieldsResourceWithRawResponse(self._cdn.shields) + + @cached_property + def origin_groups(self) -> OriginGroupsResourceWithRawResponse: + return OriginGroupsResourceWithRawResponse(self._cdn.origin_groups) + + @cached_property + def rule_templates(self) -> RuleTemplatesResourceWithRawResponse: + return RuleTemplatesResourceWithRawResponse(self._cdn.rule_templates) + + @cached_property + def certificates(self) -> CertificatesResourceWithRawResponse: + return CertificatesResourceWithRawResponse(self._cdn.certificates) + + @cached_property + def trusted_ca_certificates(self) -> TrustedCaCertificatesResourceWithRawResponse: + return TrustedCaCertificatesResourceWithRawResponse(self._cdn.trusted_ca_certificates) + + @cached_property + def audit_logs(self) -> AuditLogsResourceWithRawResponse: + return AuditLogsResourceWithRawResponse(self._cdn.audit_logs) + + @cached_property + def logs(self) -> LogsResourceWithRawResponse: + return LogsResourceWithRawResponse(self._cdn.logs) + + @cached_property + def logs_uploader(self) -> LogsUploaderResourceWithRawResponse: + return LogsUploaderResourceWithRawResponse(self._cdn.logs_uploader) + + @cached_property + def statistics(self) -> StatisticsResourceWithRawResponse: + return StatisticsResourceWithRawResponse(self._cdn.statistics) + + @cached_property + def network_capacity(self) -> NetworkCapacityResourceWithRawResponse: + return NetworkCapacityResourceWithRawResponse(self._cdn.network_capacity) + + @cached_property + def metrics(self) -> MetricsResourceWithRawResponse: + return MetricsResourceWithRawResponse(self._cdn.metrics) + + @cached_property + def ip_ranges(self) -> IPRangesResourceWithRawResponse: + return IPRangesResourceWithRawResponse(self._cdn.ip_ranges) + + +class AsyncCDNResourceWithRawResponse: + def __init__(self, cdn: AsyncCDNResource) -> None: + self._cdn = cdn + + self.get_account_limits = async_to_raw_response_wrapper( + cdn.get_account_limits, + ) + self.get_account_overview = async_to_raw_response_wrapper( + cdn.get_account_overview, + ) + self.get_available_features = async_to_raw_response_wrapper( + cdn.get_available_features, + ) + self.list_alibaba_regions = async_to_raw_response_wrapper( + cdn.list_alibaba_regions, + ) + self.list_aws_regions = async_to_raw_response_wrapper( + cdn.list_aws_regions, + ) + self.list_purge_statuses = async_to_raw_response_wrapper( + cdn.list_purge_statuses, + ) + self.update_account = async_to_raw_response_wrapper( + cdn.update_account, + ) + + @cached_property + def cdn_resources(self) -> AsyncCDNResourcesResourceWithRawResponse: + return AsyncCDNResourcesResourceWithRawResponse(self._cdn.cdn_resources) + + @cached_property + def shields(self) -> AsyncShieldsResourceWithRawResponse: + return AsyncShieldsResourceWithRawResponse(self._cdn.shields) + + @cached_property + def origin_groups(self) -> AsyncOriginGroupsResourceWithRawResponse: + return AsyncOriginGroupsResourceWithRawResponse(self._cdn.origin_groups) + + @cached_property + def rule_templates(self) -> AsyncRuleTemplatesResourceWithRawResponse: + return AsyncRuleTemplatesResourceWithRawResponse(self._cdn.rule_templates) + + @cached_property + def certificates(self) -> AsyncCertificatesResourceWithRawResponse: + return AsyncCertificatesResourceWithRawResponse(self._cdn.certificates) + + @cached_property + def trusted_ca_certificates(self) -> AsyncTrustedCaCertificatesResourceWithRawResponse: + return AsyncTrustedCaCertificatesResourceWithRawResponse(self._cdn.trusted_ca_certificates) + + @cached_property + def audit_logs(self) -> AsyncAuditLogsResourceWithRawResponse: + return AsyncAuditLogsResourceWithRawResponse(self._cdn.audit_logs) + + @cached_property + def logs(self) -> AsyncLogsResourceWithRawResponse: + return AsyncLogsResourceWithRawResponse(self._cdn.logs) + + @cached_property + def logs_uploader(self) -> AsyncLogsUploaderResourceWithRawResponse: + return AsyncLogsUploaderResourceWithRawResponse(self._cdn.logs_uploader) + + @cached_property + def statistics(self) -> AsyncStatisticsResourceWithRawResponse: + return AsyncStatisticsResourceWithRawResponse(self._cdn.statistics) + + @cached_property + def network_capacity(self) -> AsyncNetworkCapacityResourceWithRawResponse: + return AsyncNetworkCapacityResourceWithRawResponse(self._cdn.network_capacity) + + @cached_property + def metrics(self) -> AsyncMetricsResourceWithRawResponse: + return AsyncMetricsResourceWithRawResponse(self._cdn.metrics) + + @cached_property + def ip_ranges(self) -> AsyncIPRangesResourceWithRawResponse: + return AsyncIPRangesResourceWithRawResponse(self._cdn.ip_ranges) + + +class CDNResourceWithStreamingResponse: + def __init__(self, cdn: CDNResource) -> None: + self._cdn = cdn + + self.get_account_limits = to_streamed_response_wrapper( + cdn.get_account_limits, + ) + self.get_account_overview = to_streamed_response_wrapper( + cdn.get_account_overview, + ) + self.get_available_features = to_streamed_response_wrapper( + cdn.get_available_features, + ) + self.list_alibaba_regions = to_streamed_response_wrapper( + cdn.list_alibaba_regions, + ) + self.list_aws_regions = to_streamed_response_wrapper( + cdn.list_aws_regions, + ) + self.list_purge_statuses = to_streamed_response_wrapper( + cdn.list_purge_statuses, + ) + self.update_account = to_streamed_response_wrapper( + cdn.update_account, + ) + + @cached_property + def cdn_resources(self) -> CDNResourcesResourceWithStreamingResponse: + return CDNResourcesResourceWithStreamingResponse(self._cdn.cdn_resources) + + @cached_property + def shields(self) -> ShieldsResourceWithStreamingResponse: + return ShieldsResourceWithStreamingResponse(self._cdn.shields) + + @cached_property + def origin_groups(self) -> OriginGroupsResourceWithStreamingResponse: + return OriginGroupsResourceWithStreamingResponse(self._cdn.origin_groups) + + @cached_property + def rule_templates(self) -> RuleTemplatesResourceWithStreamingResponse: + return RuleTemplatesResourceWithStreamingResponse(self._cdn.rule_templates) + + @cached_property + def certificates(self) -> CertificatesResourceWithStreamingResponse: + return CertificatesResourceWithStreamingResponse(self._cdn.certificates) + + @cached_property + def trusted_ca_certificates(self) -> TrustedCaCertificatesResourceWithStreamingResponse: + return TrustedCaCertificatesResourceWithStreamingResponse(self._cdn.trusted_ca_certificates) + + @cached_property + def audit_logs(self) -> AuditLogsResourceWithStreamingResponse: + return AuditLogsResourceWithStreamingResponse(self._cdn.audit_logs) + + @cached_property + def logs(self) -> LogsResourceWithStreamingResponse: + return LogsResourceWithStreamingResponse(self._cdn.logs) + + @cached_property + def logs_uploader(self) -> LogsUploaderResourceWithStreamingResponse: + return LogsUploaderResourceWithStreamingResponse(self._cdn.logs_uploader) + + @cached_property + def statistics(self) -> StatisticsResourceWithStreamingResponse: + return StatisticsResourceWithStreamingResponse(self._cdn.statistics) + + @cached_property + def network_capacity(self) -> NetworkCapacityResourceWithStreamingResponse: + return NetworkCapacityResourceWithStreamingResponse(self._cdn.network_capacity) + + @cached_property + def metrics(self) -> MetricsResourceWithStreamingResponse: + return MetricsResourceWithStreamingResponse(self._cdn.metrics) + + @cached_property + def ip_ranges(self) -> IPRangesResourceWithStreamingResponse: + return IPRangesResourceWithStreamingResponse(self._cdn.ip_ranges) + + +class AsyncCDNResourceWithStreamingResponse: + def __init__(self, cdn: AsyncCDNResource) -> None: + self._cdn = cdn + + self.get_account_limits = async_to_streamed_response_wrapper( + cdn.get_account_limits, + ) + self.get_account_overview = async_to_streamed_response_wrapper( + cdn.get_account_overview, + ) + self.get_available_features = async_to_streamed_response_wrapper( + cdn.get_available_features, + ) + self.list_alibaba_regions = async_to_streamed_response_wrapper( + cdn.list_alibaba_regions, + ) + self.list_aws_regions = async_to_streamed_response_wrapper( + cdn.list_aws_regions, + ) + self.list_purge_statuses = async_to_streamed_response_wrapper( + cdn.list_purge_statuses, + ) + self.update_account = async_to_streamed_response_wrapper( + cdn.update_account, + ) + + @cached_property + def cdn_resources(self) -> AsyncCDNResourcesResourceWithStreamingResponse: + return AsyncCDNResourcesResourceWithStreamingResponse(self._cdn.cdn_resources) + + @cached_property + def shields(self) -> AsyncShieldsResourceWithStreamingResponse: + return AsyncShieldsResourceWithStreamingResponse(self._cdn.shields) + + @cached_property + def origin_groups(self) -> AsyncOriginGroupsResourceWithStreamingResponse: + return AsyncOriginGroupsResourceWithStreamingResponse(self._cdn.origin_groups) + + @cached_property + def rule_templates(self) -> AsyncRuleTemplatesResourceWithStreamingResponse: + return AsyncRuleTemplatesResourceWithStreamingResponse(self._cdn.rule_templates) + + @cached_property + def certificates(self) -> AsyncCertificatesResourceWithStreamingResponse: + return AsyncCertificatesResourceWithStreamingResponse(self._cdn.certificates) + + @cached_property + def trusted_ca_certificates(self) -> AsyncTrustedCaCertificatesResourceWithStreamingResponse: + return AsyncTrustedCaCertificatesResourceWithStreamingResponse(self._cdn.trusted_ca_certificates) + + @cached_property + def audit_logs(self) -> AsyncAuditLogsResourceWithStreamingResponse: + return AsyncAuditLogsResourceWithStreamingResponse(self._cdn.audit_logs) + + @cached_property + def logs(self) -> AsyncLogsResourceWithStreamingResponse: + return AsyncLogsResourceWithStreamingResponse(self._cdn.logs) + + @cached_property + def logs_uploader(self) -> AsyncLogsUploaderResourceWithStreamingResponse: + return AsyncLogsUploaderResourceWithStreamingResponse(self._cdn.logs_uploader) + + @cached_property + def statistics(self) -> AsyncStatisticsResourceWithStreamingResponse: + return AsyncStatisticsResourceWithStreamingResponse(self._cdn.statistics) + + @cached_property + def network_capacity(self) -> AsyncNetworkCapacityResourceWithStreamingResponse: + return AsyncNetworkCapacityResourceWithStreamingResponse(self._cdn.network_capacity) + + @cached_property + def metrics(self) -> AsyncMetricsResourceWithStreamingResponse: + return AsyncMetricsResourceWithStreamingResponse(self._cdn.metrics) + + @cached_property + def ip_ranges(self) -> AsyncIPRangesResourceWithStreamingResponse: + return AsyncIPRangesResourceWithStreamingResponse(self._cdn.ip_ranges) diff --git a/src/gcore/resources/cdn/cdn_resources/__init__.py b/src/gcore/resources/cdn/cdn_resources/__init__.py new file mode 100644 index 00000000..b8fee4c6 --- /dev/null +++ b/src/gcore/resources/cdn/cdn_resources/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .rules import ( + RulesResource, + AsyncRulesResource, + RulesResourceWithRawResponse, + AsyncRulesResourceWithRawResponse, + RulesResourceWithStreamingResponse, + AsyncRulesResourceWithStreamingResponse, +) +from .shield import ( + ShieldResource, + AsyncShieldResource, + ShieldResourceWithRawResponse, + AsyncShieldResourceWithRawResponse, + ShieldResourceWithStreamingResponse, + AsyncShieldResourceWithStreamingResponse, +) +from .cdn_resources import ( + CDNResourcesResource, + AsyncCDNResourcesResource, + CDNResourcesResourceWithRawResponse, + AsyncCDNResourcesResourceWithRawResponse, + CDNResourcesResourceWithStreamingResponse, + AsyncCDNResourcesResourceWithStreamingResponse, +) + +__all__ = [ + "ShieldResource", + "AsyncShieldResource", + "ShieldResourceWithRawResponse", + "AsyncShieldResourceWithRawResponse", + "ShieldResourceWithStreamingResponse", + "AsyncShieldResourceWithStreamingResponse", + "RulesResource", + "AsyncRulesResource", + "RulesResourceWithRawResponse", + "AsyncRulesResourceWithRawResponse", + "RulesResourceWithStreamingResponse", + "AsyncRulesResourceWithStreamingResponse", + "CDNResourcesResource", + "AsyncCDNResourcesResource", + "CDNResourcesResourceWithRawResponse", + "AsyncCDNResourcesResourceWithRawResponse", + "CDNResourcesResourceWithStreamingResponse", + "AsyncCDNResourcesResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cdn/cdn_resources/cdn_resources.py b/src/gcore/resources/cdn/cdn_resources/cdn_resources.py new file mode 100644 index 00000000..52c7821e --- /dev/null +++ b/src/gcore/resources/cdn/cdn_resources/cdn_resources.py @@ -0,0 +1,2028 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, overload + +import httpx + +from .rules import ( + RulesResource, + AsyncRulesResource, + RulesResourceWithRawResponse, + AsyncRulesResourceWithRawResponse, + RulesResourceWithStreamingResponse, + AsyncRulesResourceWithStreamingResponse, +) +from .shield import ( + ShieldResource, + AsyncShieldResource, + ShieldResourceWithRawResponse, + AsyncShieldResourceWithRawResponse, + ShieldResourceWithStreamingResponse, + AsyncShieldResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....types.cdn import ( + cdn_resource_list_params, + cdn_resource_purge_params, + cdn_resource_create_params, + cdn_resource_update_params, + cdn_resource_replace_params, + cdn_resource_prefetch_params, +) +from ...._base_client import make_request_options +from ....types.cdn.cdn_resource import CDNResource +from ....types.cdn.cdn_resource_list import CDNResourceList + +__all__ = ["CDNResourcesResource", "AsyncCDNResourcesResource"] + + +class CDNResourcesResource(SyncAPIResource): + @cached_property + def shield(self) -> ShieldResource: + return ShieldResource(self._client) + + @cached_property + def rules(self) -> RulesResource: + return RulesResource(self._client) + + @cached_property + def with_raw_response(self) -> CDNResourcesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return CDNResourcesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CDNResourcesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return CDNResourcesResourceWithStreamingResponse(self) + + def create( + self, + *, + cname: str, + active: bool | Omit = omit, + description: str | Omit = omit, + name: Optional[str] | Omit = omit, + options: cdn_resource_create_params.Options | Omit = omit, + origin: str | Omit = omit, + origin_group: int | Omit = omit, + origin_protocol: Literal["HTTP", "HTTPS", "MATCH"] | Omit = omit, + primary_resource: Optional[int] | Omit = omit, + proxy_ssl_ca: Optional[int] | Omit = omit, + proxy_ssl_data: Optional[int] | Omit = omit, + proxy_ssl_enabled: bool | Omit = omit, + secondary_hostnames: SequenceNotStr[str] | Omit = omit, + ssl_data: Optional[int] | Omit = omit, + ssl_enabled: bool | Omit = omit, + waap_api_domain_enabled: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResource: + """ + Create CDN resource + + Args: + cname: Delivery domains that will be used for content delivery through a CDN. + + Delivery domains should be added to your DNS settings. + + active: Enables or disables a CDN resource. + + Possible values: + + - **true** - CDN resource is active. Content is being delivered. + - **false** - CDN resource is deactivated. Content is not being delivered. + + description: Optional comment describing the CDN resource. + + name: CDN resource name. + + options: List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. Option may + inherit its value from the global account settings. + + origin: IP address or domain name of the origin and the port, if custom port is used. + + Exactly one of `origin` or `originGroup` must be provided during resource + creation. + + origin_group: Origin group ID with which the CDN resource is associated. + + Exactly one of `origin` or `originGroup` must be provided during resource + creation. + + origin_protocol: Protocol used by CDN servers to request content from an origin source. + + Possible values: + + - **HTTPS** - CDN servers will connect to the origin via HTTPS. + - **HTTP** - CDN servers will connect to the origin via HTTP. + - **MATCH** - connection protocol will be chosen automatically (content on the + origin source should be available for the CDN both through HTTP and HTTPS). + + If protocol is not specified, HTTP is used to connect to an origin server. + + primary_resource: ID of the main CDN resource which has a shared caching zone with a reserve CDN + resource. + + If the parameter is not empty, then the current CDN resource is the reserve. You + cannot change some options, create rules, set up origin shielding, or use the + reserve CDN resource for Streaming. + + proxy_ssl_ca: ID of the trusted CA certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + + proxy_ssl_data: ID of the SSL certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + + proxy_ssl_enabled: Enables or disables SSL certificate validation of the origin server before + completing any connection. + + Possible values: + + - **true** - Origin SSL certificate validation is enabled. + - **false** - Origin SSL certificate validation is disabled. + + secondary_hostnames: Additional delivery domains (CNAMEs) that will be used to deliver content via + the CDN. + + Up to ten additional CNAMEs are possible. + + ssl_data: ID of the SSL certificate linked to the CDN resource. + + Can be used only with `"sslEnabled": true`. + + ssl_enabled: Defines whether the HTTPS protocol enabled for content delivery. + + Possible values: + + - **true** - HTTPS is enabled. + - **false** - HTTPS is disabled. + + waap_api_domain_enabled: Defines whether the associated WAAP Domain is identified as an API Domain. + + Possible values: + + - **true** - The associated WAAP Domain is designated as an API Domain. + - **false** - The associated WAAP Domain is not designated as an API Domain. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/cdn/resources", + body=maybe_transform( + { + "cname": cname, + "active": active, + "description": description, + "name": name, + "options": options, + "origin": origin, + "origin_group": origin_group, + "origin_protocol": origin_protocol, + "primary_resource": primary_resource, + "proxy_ssl_ca": proxy_ssl_ca, + "proxy_ssl_data": proxy_ssl_data, + "proxy_ssl_enabled": proxy_ssl_enabled, + "secondary_hostnames": secondary_hostnames, + "ssl_data": ssl_data, + "ssl_enabled": ssl_enabled, + "waap_api_domain_enabled": waap_api_domain_enabled, + }, + cdn_resource_create_params.CDNResourceCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResource, + ) + + def update( + self, + resource_id: int, + *, + active: bool | Omit = omit, + description: str | Omit = omit, + name: Optional[str] | Omit = omit, + options: cdn_resource_update_params.Options | Omit = omit, + origin_group: int | Omit = omit, + origin_protocol: Literal["HTTP", "HTTPS", "MATCH"] | Omit = omit, + proxy_ssl_ca: Optional[int] | Omit = omit, + proxy_ssl_data: Optional[int] | Omit = omit, + proxy_ssl_enabled: bool | Omit = omit, + secondary_hostnames: SequenceNotStr[str] | Omit = omit, + ssl_data: Optional[int] | Omit = omit, + ssl_enabled: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResource: + """ + Change CDN resource + + Args: + active: Enables or disables a CDN resource. + + Possible values: + + - **true** - CDN resource is active. Content is being delivered. + - **false** - CDN resource is deactivated. Content is not being delivered. + + description: Optional comment describing the CDN resource. + + name: CDN resource name. + + options: List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. Option may + inherit its value from the global account settings. + + origin_group: Origin group ID with which the CDN resource is associated. + + origin_protocol: Protocol used by CDN servers to request content from an origin source. + + Possible values: + + - **HTTPS** - CDN servers will connect to the origin via HTTPS. + - **HTTP** - CDN servers will connect to the origin via HTTP. + - **MATCH** - connection protocol will be chosen automatically (content on the + origin source should be available for the CDN both through HTTP and HTTPS). + + If protocol is not specified, HTTP is used to connect to an origin server. + + proxy_ssl_ca: ID of the trusted CA certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + + proxy_ssl_data: ID of the SSL certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + + proxy_ssl_enabled: Enables or disables SSL certificate validation of the origin server before + completing any connection. + + Possible values: + + - **true** - Origin SSL certificate validation is enabled. + - **false** - Origin SSL certificate validation is disabled. + + secondary_hostnames: Additional delivery domains (CNAMEs) that will be used to deliver content via + the CDN. + + Up to ten additional CNAMEs are possible. + + ssl_data: ID of the SSL certificate linked to the CDN resource. + + Can be used only with `"sslEnabled": true`. + + ssl_enabled: Defines whether the HTTPS protocol enabled for content delivery. + + Possible values: + + - **true** - HTTPS is enabled. + - **false** - HTTPS is disabled. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/cdn/resources/{resource_id}", + body=maybe_transform( + { + "active": active, + "description": description, + "name": name, + "options": options, + "origin_group": origin_group, + "origin_protocol": origin_protocol, + "proxy_ssl_ca": proxy_ssl_ca, + "proxy_ssl_data": proxy_ssl_data, + "proxy_ssl_enabled": proxy_ssl_enabled, + "secondary_hostnames": secondary_hostnames, + "ssl_data": ssl_data, + "ssl_enabled": ssl_enabled, + }, + cdn_resource_update_params.CDNResourceUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResource, + ) + + def list( + self, + *, + cname: str | Omit = omit, + deleted: bool | Omit = omit, + enabled: bool | Omit = omit, + max_created: str | Omit = omit, + min_created: str | Omit = omit, + origin_group: int | Omit = omit, + rules: str | Omit = omit, + secondary_hostnames: str | Omit = omit, + shield_dc: str | Omit = omit, + shielded: bool | Omit = omit, + ssl_data: int | Omit = omit, + ssl_data_in: int | Omit = omit, + ssl_enabled: bool | Omit = omit, + status: Literal["active", "processed", "suspended", "deleted"] | Omit = omit, + suspend: bool | Omit = omit, + vp_enabled: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResourceList: + """ + Get information about all CDN resources in your account. + + Args: + cname: Delivery domain (CNAME) of the CDN resource. + + deleted: Defines whether a CDN resource has been deleted. + + Possible values: + + - **true** - CDN resource has been deleted. + - **false** - CDN resource has not been deleted. + + enabled: Enables or disables a CDN resource change by a user. + + Possible values: + + - **true** - CDN resource is enabled. + - **false** - CDN resource is disabled. + + max_created: Most recent date of CDN resource creation for which CDN resources should be + returned (ISO 8601/RFC 3339 format, UTC.) + + min_created: Earliest date of CDN resource creation for which CDN resources should be + returned (ISO 8601/RFC 3339 format, UTC.) + + origin_group: Origin group ID. + + rules: Rule name or pattern. + + secondary_hostnames: Additional delivery domains (CNAMEs) of the CDN resource. + + shield_dc: Name of the origin shielding data center location. + + shielded: Defines whether origin shielding is enabled for the CDN resource. + + Possible values: + + - **true** - Origin shielding is enabled for the CDN resource. + - **false** - Origin shielding is disabled for the CDN resource. + + ssl_data: SSL certificate ID. + + ssl_data_in: SSL certificates IDs. + + Example: + + - ?`sslData_in`=1643,1644,1652 + + ssl_enabled: Defines whether the HTTPS protocol is enabled for content delivery. + + Possible values: + + - **true** - HTTPS protocol is enabled for CDN resource. + - **false** - HTTPS protocol is disabled for CDN resource. + + status: CDN resource status. + + suspend: Defines whether the CDN resource was automatically suspended by the system. + + Possible values: + + - **true** - CDN resource is selected for automatic suspension in the next 7 + days. + - **false** - CDN resource is not selected for automatic suspension. + + vp_enabled: Defines whether the CDN resource is integrated with the Streaming platform. + + Possible values: + + - **true** - CDN resource is used for Streaming platform. + - **false** - CDN resource is not used for Streaming platform. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/resources", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cname": cname, + "deleted": deleted, + "enabled": enabled, + "max_created": max_created, + "min_created": min_created, + "origin_group": origin_group, + "rules": rules, + "secondary_hostnames": secondary_hostnames, + "shield_dc": shield_dc, + "shielded": shielded, + "ssl_data": ssl_data, + "ssl_data_in": ssl_data_in, + "ssl_enabled": ssl_enabled, + "status": status, + "suspend": suspend, + "vp_enabled": vp_enabled, + }, + cdn_resource_list_params.CDNResourceListParams, + ), + ), + cast_to=CDNResourceList, + ) + + def delete( + self, + resource_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete the CDN resource from the system permanently. + + Notes: + + - **Deactivation Requirement**: Set the `active` attribute to `false` before + deletion. + - **Statistics Availability**: Statistics will be available for **365 days** + after deletion through the + [statistics endpoints](/docs/api-reference/cdn/cdn-statistics/cdn-resource-statistics). + - **Irreversibility**: This action is irreversible. Once deleted, the CDN + resource cannot be recovered. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cdn/resources/{resource_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + resource_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResource: + """ + Get CDN resource details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cdn/resources/{resource_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResource, + ) + + def prefetch( + self, + resource_id: int, + *, + paths: SequenceNotStr[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Pre-populate files to a CDN cache before users requests. + + Prefetch is recommended + only for files that **more than 200 MB** and **less than 5 GB**. + + You can make one prefetch request for a CDN resource per minute. One request for + prefetch may content only up to 100 paths to files. + + The time of procedure depends on the number and size of the files. + + If you need to update files stored in the CDN, first purge these files and then + prefetch. + + Args: + paths: Paths to files that should be pre-populated to the CDN. + + Paths to the files should be specified without a domain name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/cdn/resources/{resource_id}/prefetch", + body=maybe_transform({"paths": paths}, cdn_resource_prefetch_params.CDNResourcePrefetchParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def prevalidate_ssl_le_certificate( + self, + resource_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Check whether a Let's Encrypt certificate can be issued for the CDN resource. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/cdn/resources/{resource_id}/ssl/le/pre-validate", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + @overload + def purge( + self, + resource_id: int, + *, + urls: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete cache from CDN servers. + + This is necessary to update CDN content. + + We have different limits for different purge types: + + - **Purge all cache** - One purge request for a CDN resource per minute. + - **Purge by URL** - Two purge requests for a CDN resource per minute. One purge + request is limited to 100 URLs. + - **Purge by pattern** - One purge request for a CDN resource per minute. One + purge request is limited to 10 patterns. + + Args: + urls: **Purge by URL** clears the cache of a specific files. This purge type is + recommended. + + Specify file URLs including query strings. URLs should start with / without a + domain name. + + Purge by URL depends on the following CDN options: + + 1. "vary response header" is used. If your origin serves variants of the same + content depending on the Vary HTTP response header, purge by URL will delete + only one version of the file. + 2. "slice" is used. If you update several files in the origin without clearing + the CDN cache, purge by URL will delete only the first slice (with bytes=0… + .) + 3. "ignoreQueryString" is used. Don’t specify parameters in the purge request. + 4. "query_params_blacklist" is used. Only files with the listed in the option + parameters will be cached as different objects. Files with other parameters + will be cached as one object. In this case, specify the listed parameters in + the Purge request. Don't specify other parameters. + 5. "query_params_whitelist" is used. Files with listed in the option parameters + will be cached as one object. Files with other parameters will be cached as + different objects. In this case, specify other parameters (if any) besides + the ones listed in the purge request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def purge( + self, + resource_id: int, + *, + paths: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete cache from CDN servers. + + This is necessary to update CDN content. + + We have different limits for different purge types: + + - **Purge all cache** - One purge request for a CDN resource per minute. + - **Purge by URL** - Two purge requests for a CDN resource per minute. One purge + request is limited to 100 URLs. + - **Purge by pattern** - One purge request for a CDN resource per minute. One + purge request is limited to 10 patterns. + + Args: + paths: **Purge by pattern** clears the cache that matches the pattern. + + Use _ operator, which replaces any number of symbols in your path. It's + important to note that wildcard usage (_) is permitted only at the end of a + pattern. + + Query string added to any patterns will be ignored, and purge request will be + processed as if there weren't any parameters. + + Purge by pattern is recursive. Both /path and /path* will result in recursive + purging, meaning all content under the specified path will be affected. As such, + using the pattern /path* is functionally equivalent to simply using /path. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def purge( + self, + resource_id: int, + *, + paths: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete cache from CDN servers. + + This is necessary to update CDN content. + + We have different limits for different purge types: + + - **Purge all cache** - One purge request for a CDN resource per minute. + - **Purge by URL** - Two purge requests for a CDN resource per minute. One purge + request is limited to 100 URLs. + - **Purge by pattern** - One purge request for a CDN resource per minute. One + purge request is limited to 10 patterns. + + Args: + paths: **Purge all cache** clears the entire cache for the CDN resource. + + Specify an empty array to purge all content for the resource. + + When you purge all assets, CDN servers request content from your origin server + and cause a high load. Therefore, we recommend to use purge by URL for large + content quantities. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + def purge( + self, + resource_id: int, + *, + urls: SequenceNotStr[str] | Omit = omit, + paths: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/cdn/resources/{resource_id}/purge", + body=maybe_transform( + { + "urls": urls, + "paths": paths, + }, + cdn_resource_purge_params.CDNResourcePurgeParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def replace( + self, + resource_id: int, + *, + origin_group: int, + active: bool | Omit = omit, + description: str | Omit = omit, + name: Optional[str] | Omit = omit, + options: cdn_resource_replace_params.Options | Omit = omit, + origin_protocol: Literal["HTTP", "HTTPS", "MATCH"] | Omit = omit, + proxy_ssl_ca: Optional[int] | Omit = omit, + proxy_ssl_data: Optional[int] | Omit = omit, + proxy_ssl_enabled: bool | Omit = omit, + secondary_hostnames: SequenceNotStr[str] | Omit = omit, + ssl_data: Optional[int] | Omit = omit, + ssl_enabled: bool | Omit = omit, + waap_api_domain_enabled: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResource: + """ + Change CDN resource + + Args: + origin_group: Origin group ID with which the CDN resource is associated. + + active: Enables or disables a CDN resource. + + Possible values: + + - **true** - CDN resource is active. Content is being delivered. + - **false** - CDN resource is deactivated. Content is not being delivered. + + description: Optional comment describing the CDN resource. + + name: CDN resource name. + + options: List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. Option may + inherit its value from the global account settings. + + origin_protocol: Protocol used by CDN servers to request content from an origin source. + + Possible values: + + - **HTTPS** - CDN servers will connect to the origin via HTTPS. + - **HTTP** - CDN servers will connect to the origin via HTTP. + - **MATCH** - connection protocol will be chosen automatically (content on the + origin source should be available for the CDN both through HTTP and HTTPS). + + If protocol is not specified, HTTP is used to connect to an origin server. + + proxy_ssl_ca: ID of the trusted CA certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + + proxy_ssl_data: ID of the SSL certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + + proxy_ssl_enabled: Enables or disables SSL certificate validation of the origin server before + completing any connection. + + Possible values: + + - **true** - Origin SSL certificate validation is enabled. + - **false** - Origin SSL certificate validation is disabled. + + secondary_hostnames: Additional delivery domains (CNAMEs) that will be used to deliver content via + the CDN. + + Up to ten additional CNAMEs are possible. + + ssl_data: ID of the SSL certificate linked to the CDN resource. + + Can be used only with `"sslEnabled": true`. + + ssl_enabled: Defines whether the HTTPS protocol enabled for content delivery. + + Possible values: + + - **true** - HTTPS is enabled. + - **false** - HTTPS is disabled. + + waap_api_domain_enabled: Defines whether the associated WAAP Domain is identified as an API Domain. + + Possible values: + + - **true** - The associated WAAP Domain is designated as an API Domain. + - **false** - The associated WAAP Domain is not designated as an API Domain. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/cdn/resources/{resource_id}", + body=maybe_transform( + { + "origin_group": origin_group, + "active": active, + "description": description, + "name": name, + "options": options, + "origin_protocol": origin_protocol, + "proxy_ssl_ca": proxy_ssl_ca, + "proxy_ssl_data": proxy_ssl_data, + "proxy_ssl_enabled": proxy_ssl_enabled, + "secondary_hostnames": secondary_hostnames, + "ssl_data": ssl_data, + "ssl_enabled": ssl_enabled, + "waap_api_domain_enabled": waap_api_domain_enabled, + }, + cdn_resource_replace_params.CDNResourceReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResource, + ) + + +class AsyncCDNResourcesResource(AsyncAPIResource): + @cached_property + def shield(self) -> AsyncShieldResource: + return AsyncShieldResource(self._client) + + @cached_property + def rules(self) -> AsyncRulesResource: + return AsyncRulesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncCDNResourcesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncCDNResourcesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCDNResourcesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncCDNResourcesResourceWithStreamingResponse(self) + + async def create( + self, + *, + cname: str, + active: bool | Omit = omit, + description: str | Omit = omit, + name: Optional[str] | Omit = omit, + options: cdn_resource_create_params.Options | Omit = omit, + origin: str | Omit = omit, + origin_group: int | Omit = omit, + origin_protocol: Literal["HTTP", "HTTPS", "MATCH"] | Omit = omit, + primary_resource: Optional[int] | Omit = omit, + proxy_ssl_ca: Optional[int] | Omit = omit, + proxy_ssl_data: Optional[int] | Omit = omit, + proxy_ssl_enabled: bool | Omit = omit, + secondary_hostnames: SequenceNotStr[str] | Omit = omit, + ssl_data: Optional[int] | Omit = omit, + ssl_enabled: bool | Omit = omit, + waap_api_domain_enabled: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResource: + """ + Create CDN resource + + Args: + cname: Delivery domains that will be used for content delivery through a CDN. + + Delivery domains should be added to your DNS settings. + + active: Enables or disables a CDN resource. + + Possible values: + + - **true** - CDN resource is active. Content is being delivered. + - **false** - CDN resource is deactivated. Content is not being delivered. + + description: Optional comment describing the CDN resource. + + name: CDN resource name. + + options: List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. Option may + inherit its value from the global account settings. + + origin: IP address or domain name of the origin and the port, if custom port is used. + + Exactly one of `origin` or `originGroup` must be provided during resource + creation. + + origin_group: Origin group ID with which the CDN resource is associated. + + Exactly one of `origin` or `originGroup` must be provided during resource + creation. + + origin_protocol: Protocol used by CDN servers to request content from an origin source. + + Possible values: + + - **HTTPS** - CDN servers will connect to the origin via HTTPS. + - **HTTP** - CDN servers will connect to the origin via HTTP. + - **MATCH** - connection protocol will be chosen automatically (content on the + origin source should be available for the CDN both through HTTP and HTTPS). + + If protocol is not specified, HTTP is used to connect to an origin server. + + primary_resource: ID of the main CDN resource which has a shared caching zone with a reserve CDN + resource. + + If the parameter is not empty, then the current CDN resource is the reserve. You + cannot change some options, create rules, set up origin shielding, or use the + reserve CDN resource for Streaming. + + proxy_ssl_ca: ID of the trusted CA certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + + proxy_ssl_data: ID of the SSL certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + + proxy_ssl_enabled: Enables or disables SSL certificate validation of the origin server before + completing any connection. + + Possible values: + + - **true** - Origin SSL certificate validation is enabled. + - **false** - Origin SSL certificate validation is disabled. + + secondary_hostnames: Additional delivery domains (CNAMEs) that will be used to deliver content via + the CDN. + + Up to ten additional CNAMEs are possible. + + ssl_data: ID of the SSL certificate linked to the CDN resource. + + Can be used only with `"sslEnabled": true`. + + ssl_enabled: Defines whether the HTTPS protocol enabled for content delivery. + + Possible values: + + - **true** - HTTPS is enabled. + - **false** - HTTPS is disabled. + + waap_api_domain_enabled: Defines whether the associated WAAP Domain is identified as an API Domain. + + Possible values: + + - **true** - The associated WAAP Domain is designated as an API Domain. + - **false** - The associated WAAP Domain is not designated as an API Domain. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/cdn/resources", + body=await async_maybe_transform( + { + "cname": cname, + "active": active, + "description": description, + "name": name, + "options": options, + "origin": origin, + "origin_group": origin_group, + "origin_protocol": origin_protocol, + "primary_resource": primary_resource, + "proxy_ssl_ca": proxy_ssl_ca, + "proxy_ssl_data": proxy_ssl_data, + "proxy_ssl_enabled": proxy_ssl_enabled, + "secondary_hostnames": secondary_hostnames, + "ssl_data": ssl_data, + "ssl_enabled": ssl_enabled, + "waap_api_domain_enabled": waap_api_domain_enabled, + }, + cdn_resource_create_params.CDNResourceCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResource, + ) + + async def update( + self, + resource_id: int, + *, + active: bool | Omit = omit, + description: str | Omit = omit, + name: Optional[str] | Omit = omit, + options: cdn_resource_update_params.Options | Omit = omit, + origin_group: int | Omit = omit, + origin_protocol: Literal["HTTP", "HTTPS", "MATCH"] | Omit = omit, + proxy_ssl_ca: Optional[int] | Omit = omit, + proxy_ssl_data: Optional[int] | Omit = omit, + proxy_ssl_enabled: bool | Omit = omit, + secondary_hostnames: SequenceNotStr[str] | Omit = omit, + ssl_data: Optional[int] | Omit = omit, + ssl_enabled: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResource: + """ + Change CDN resource + + Args: + active: Enables or disables a CDN resource. + + Possible values: + + - **true** - CDN resource is active. Content is being delivered. + - **false** - CDN resource is deactivated. Content is not being delivered. + + description: Optional comment describing the CDN resource. + + name: CDN resource name. + + options: List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. Option may + inherit its value from the global account settings. + + origin_group: Origin group ID with which the CDN resource is associated. + + origin_protocol: Protocol used by CDN servers to request content from an origin source. + + Possible values: + + - **HTTPS** - CDN servers will connect to the origin via HTTPS. + - **HTTP** - CDN servers will connect to the origin via HTTP. + - **MATCH** - connection protocol will be chosen automatically (content on the + origin source should be available for the CDN both through HTTP and HTTPS). + + If protocol is not specified, HTTP is used to connect to an origin server. + + proxy_ssl_ca: ID of the trusted CA certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + + proxy_ssl_data: ID of the SSL certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + + proxy_ssl_enabled: Enables or disables SSL certificate validation of the origin server before + completing any connection. + + Possible values: + + - **true** - Origin SSL certificate validation is enabled. + - **false** - Origin SSL certificate validation is disabled. + + secondary_hostnames: Additional delivery domains (CNAMEs) that will be used to deliver content via + the CDN. + + Up to ten additional CNAMEs are possible. + + ssl_data: ID of the SSL certificate linked to the CDN resource. + + Can be used only with `"sslEnabled": true`. + + ssl_enabled: Defines whether the HTTPS protocol enabled for content delivery. + + Possible values: + + - **true** - HTTPS is enabled. + - **false** - HTTPS is disabled. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/cdn/resources/{resource_id}", + body=await async_maybe_transform( + { + "active": active, + "description": description, + "name": name, + "options": options, + "origin_group": origin_group, + "origin_protocol": origin_protocol, + "proxy_ssl_ca": proxy_ssl_ca, + "proxy_ssl_data": proxy_ssl_data, + "proxy_ssl_enabled": proxy_ssl_enabled, + "secondary_hostnames": secondary_hostnames, + "ssl_data": ssl_data, + "ssl_enabled": ssl_enabled, + }, + cdn_resource_update_params.CDNResourceUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResource, + ) + + async def list( + self, + *, + cname: str | Omit = omit, + deleted: bool | Omit = omit, + enabled: bool | Omit = omit, + max_created: str | Omit = omit, + min_created: str | Omit = omit, + origin_group: int | Omit = omit, + rules: str | Omit = omit, + secondary_hostnames: str | Omit = omit, + shield_dc: str | Omit = omit, + shielded: bool | Omit = omit, + ssl_data: int | Omit = omit, + ssl_data_in: int | Omit = omit, + ssl_enabled: bool | Omit = omit, + status: Literal["active", "processed", "suspended", "deleted"] | Omit = omit, + suspend: bool | Omit = omit, + vp_enabled: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResourceList: + """ + Get information about all CDN resources in your account. + + Args: + cname: Delivery domain (CNAME) of the CDN resource. + + deleted: Defines whether a CDN resource has been deleted. + + Possible values: + + - **true** - CDN resource has been deleted. + - **false** - CDN resource has not been deleted. + + enabled: Enables or disables a CDN resource change by a user. + + Possible values: + + - **true** - CDN resource is enabled. + - **false** - CDN resource is disabled. + + max_created: Most recent date of CDN resource creation for which CDN resources should be + returned (ISO 8601/RFC 3339 format, UTC.) + + min_created: Earliest date of CDN resource creation for which CDN resources should be + returned (ISO 8601/RFC 3339 format, UTC.) + + origin_group: Origin group ID. + + rules: Rule name or pattern. + + secondary_hostnames: Additional delivery domains (CNAMEs) of the CDN resource. + + shield_dc: Name of the origin shielding data center location. + + shielded: Defines whether origin shielding is enabled for the CDN resource. + + Possible values: + + - **true** - Origin shielding is enabled for the CDN resource. + - **false** - Origin shielding is disabled for the CDN resource. + + ssl_data: SSL certificate ID. + + ssl_data_in: SSL certificates IDs. + + Example: + + - ?`sslData_in`=1643,1644,1652 + + ssl_enabled: Defines whether the HTTPS protocol is enabled for content delivery. + + Possible values: + + - **true** - HTTPS protocol is enabled for CDN resource. + - **false** - HTTPS protocol is disabled for CDN resource. + + status: CDN resource status. + + suspend: Defines whether the CDN resource was automatically suspended by the system. + + Possible values: + + - **true** - CDN resource is selected for automatic suspension in the next 7 + days. + - **false** - CDN resource is not selected for automatic suspension. + + vp_enabled: Defines whether the CDN resource is integrated with the Streaming platform. + + Possible values: + + - **true** - CDN resource is used for Streaming platform. + - **false** - CDN resource is not used for Streaming platform. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/resources", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "cname": cname, + "deleted": deleted, + "enabled": enabled, + "max_created": max_created, + "min_created": min_created, + "origin_group": origin_group, + "rules": rules, + "secondary_hostnames": secondary_hostnames, + "shield_dc": shield_dc, + "shielded": shielded, + "ssl_data": ssl_data, + "ssl_data_in": ssl_data_in, + "ssl_enabled": ssl_enabled, + "status": status, + "suspend": suspend, + "vp_enabled": vp_enabled, + }, + cdn_resource_list_params.CDNResourceListParams, + ), + ), + cast_to=CDNResourceList, + ) + + async def delete( + self, + resource_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete the CDN resource from the system permanently. + + Notes: + + - **Deactivation Requirement**: Set the `active` attribute to `false` before + deletion. + - **Statistics Availability**: Statistics will be available for **365 days** + after deletion through the + [statistics endpoints](/docs/api-reference/cdn/cdn-statistics/cdn-resource-statistics). + - **Irreversibility**: This action is irreversible. Once deleted, the CDN + resource cannot be recovered. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cdn/resources/{resource_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + resource_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResource: + """ + Get CDN resource details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cdn/resources/{resource_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResource, + ) + + async def prefetch( + self, + resource_id: int, + *, + paths: SequenceNotStr[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Pre-populate files to a CDN cache before users requests. + + Prefetch is recommended + only for files that **more than 200 MB** and **less than 5 GB**. + + You can make one prefetch request for a CDN resource per minute. One request for + prefetch may content only up to 100 paths to files. + + The time of procedure depends on the number and size of the files. + + If you need to update files stored in the CDN, first purge these files and then + prefetch. + + Args: + paths: Paths to files that should be pre-populated to the CDN. + + Paths to the files should be specified without a domain name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/cdn/resources/{resource_id}/prefetch", + body=await async_maybe_transform({"paths": paths}, cdn_resource_prefetch_params.CDNResourcePrefetchParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def prevalidate_ssl_le_certificate( + self, + resource_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Check whether a Let's Encrypt certificate can be issued for the CDN resource. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/cdn/resources/{resource_id}/ssl/le/pre-validate", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + @overload + async def purge( + self, + resource_id: int, + *, + urls: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete cache from CDN servers. + + This is necessary to update CDN content. + + We have different limits for different purge types: + + - **Purge all cache** - One purge request for a CDN resource per minute. + - **Purge by URL** - Two purge requests for a CDN resource per minute. One purge + request is limited to 100 URLs. + - **Purge by pattern** - One purge request for a CDN resource per minute. One + purge request is limited to 10 patterns. + + Args: + urls: **Purge by URL** clears the cache of a specific files. This purge type is + recommended. + + Specify file URLs including query strings. URLs should start with / without a + domain name. + + Purge by URL depends on the following CDN options: + + 1. "vary response header" is used. If your origin serves variants of the same + content depending on the Vary HTTP response header, purge by URL will delete + only one version of the file. + 2. "slice" is used. If you update several files in the origin without clearing + the CDN cache, purge by URL will delete only the first slice (with bytes=0… + .) + 3. "ignoreQueryString" is used. Don’t specify parameters in the purge request. + 4. "query_params_blacklist" is used. Only files with the listed in the option + parameters will be cached as different objects. Files with other parameters + will be cached as one object. In this case, specify the listed parameters in + the Purge request. Don't specify other parameters. + 5. "query_params_whitelist" is used. Files with listed in the option parameters + will be cached as one object. Files with other parameters will be cached as + different objects. In this case, specify other parameters (if any) besides + the ones listed in the purge request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def purge( + self, + resource_id: int, + *, + paths: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete cache from CDN servers. + + This is necessary to update CDN content. + + We have different limits for different purge types: + + - **Purge all cache** - One purge request for a CDN resource per minute. + - **Purge by URL** - Two purge requests for a CDN resource per minute. One purge + request is limited to 100 URLs. + - **Purge by pattern** - One purge request for a CDN resource per minute. One + purge request is limited to 10 patterns. + + Args: + paths: **Purge by pattern** clears the cache that matches the pattern. + + Use _ operator, which replaces any number of symbols in your path. It's + important to note that wildcard usage (_) is permitted only at the end of a + pattern. + + Query string added to any patterns will be ignored, and purge request will be + processed as if there weren't any parameters. + + Purge by pattern is recursive. Both /path and /path* will result in recursive + purging, meaning all content under the specified path will be affected. As such, + using the pattern /path* is functionally equivalent to simply using /path. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def purge( + self, + resource_id: int, + *, + paths: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete cache from CDN servers. + + This is necessary to update CDN content. + + We have different limits for different purge types: + + - **Purge all cache** - One purge request for a CDN resource per minute. + - **Purge by URL** - Two purge requests for a CDN resource per minute. One purge + request is limited to 100 URLs. + - **Purge by pattern** - One purge request for a CDN resource per minute. One + purge request is limited to 10 patterns. + + Args: + paths: **Purge all cache** clears the entire cache for the CDN resource. + + Specify an empty array to purge all content for the resource. + + When you purge all assets, CDN servers request content from your origin server + and cause a high load. Therefore, we recommend to use purge by URL for large + content quantities. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + async def purge( + self, + resource_id: int, + *, + urls: SequenceNotStr[str] | Omit = omit, + paths: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/cdn/resources/{resource_id}/purge", + body=await async_maybe_transform( + { + "urls": urls, + "paths": paths, + }, + cdn_resource_purge_params.CDNResourcePurgeParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def replace( + self, + resource_id: int, + *, + origin_group: int, + active: bool | Omit = omit, + description: str | Omit = omit, + name: Optional[str] | Omit = omit, + options: cdn_resource_replace_params.Options | Omit = omit, + origin_protocol: Literal["HTTP", "HTTPS", "MATCH"] | Omit = omit, + proxy_ssl_ca: Optional[int] | Omit = omit, + proxy_ssl_data: Optional[int] | Omit = omit, + proxy_ssl_enabled: bool | Omit = omit, + secondary_hostnames: SequenceNotStr[str] | Omit = omit, + ssl_data: Optional[int] | Omit = omit, + ssl_enabled: bool | Omit = omit, + waap_api_domain_enabled: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResource: + """ + Change CDN resource + + Args: + origin_group: Origin group ID with which the CDN resource is associated. + + active: Enables or disables a CDN resource. + + Possible values: + + - **true** - CDN resource is active. Content is being delivered. + - **false** - CDN resource is deactivated. Content is not being delivered. + + description: Optional comment describing the CDN resource. + + name: CDN resource name. + + options: List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. Option may + inherit its value from the global account settings. + + origin_protocol: Protocol used by CDN servers to request content from an origin source. + + Possible values: + + - **HTTPS** - CDN servers will connect to the origin via HTTPS. + - **HTTP** - CDN servers will connect to the origin via HTTP. + - **MATCH** - connection protocol will be chosen automatically (content on the + origin source should be available for the CDN both through HTTP and HTTPS). + + If protocol is not specified, HTTP is used to connect to an origin server. + + proxy_ssl_ca: ID of the trusted CA certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + + proxy_ssl_data: ID of the SSL certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + + proxy_ssl_enabled: Enables or disables SSL certificate validation of the origin server before + completing any connection. + + Possible values: + + - **true** - Origin SSL certificate validation is enabled. + - **false** - Origin SSL certificate validation is disabled. + + secondary_hostnames: Additional delivery domains (CNAMEs) that will be used to deliver content via + the CDN. + + Up to ten additional CNAMEs are possible. + + ssl_data: ID of the SSL certificate linked to the CDN resource. + + Can be used only with `"sslEnabled": true`. + + ssl_enabled: Defines whether the HTTPS protocol enabled for content delivery. + + Possible values: + + - **true** - HTTPS is enabled. + - **false** - HTTPS is disabled. + + waap_api_domain_enabled: Defines whether the associated WAAP Domain is identified as an API Domain. + + Possible values: + + - **true** - The associated WAAP Domain is designated as an API Domain. + - **false** - The associated WAAP Domain is not designated as an API Domain. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/cdn/resources/{resource_id}", + body=await async_maybe_transform( + { + "origin_group": origin_group, + "active": active, + "description": description, + "name": name, + "options": options, + "origin_protocol": origin_protocol, + "proxy_ssl_ca": proxy_ssl_ca, + "proxy_ssl_data": proxy_ssl_data, + "proxy_ssl_enabled": proxy_ssl_enabled, + "secondary_hostnames": secondary_hostnames, + "ssl_data": ssl_data, + "ssl_enabled": ssl_enabled, + "waap_api_domain_enabled": waap_api_domain_enabled, + }, + cdn_resource_replace_params.CDNResourceReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResource, + ) + + +class CDNResourcesResourceWithRawResponse: + def __init__(self, cdn_resources: CDNResourcesResource) -> None: + self._cdn_resources = cdn_resources + + self.create = to_raw_response_wrapper( + cdn_resources.create, + ) + self.update = to_raw_response_wrapper( + cdn_resources.update, + ) + self.list = to_raw_response_wrapper( + cdn_resources.list, + ) + self.delete = to_raw_response_wrapper( + cdn_resources.delete, + ) + self.get = to_raw_response_wrapper( + cdn_resources.get, + ) + self.prefetch = to_raw_response_wrapper( + cdn_resources.prefetch, + ) + self.prevalidate_ssl_le_certificate = to_raw_response_wrapper( + cdn_resources.prevalidate_ssl_le_certificate, + ) + self.purge = to_raw_response_wrapper( + cdn_resources.purge, + ) + self.replace = to_raw_response_wrapper( + cdn_resources.replace, + ) + + @cached_property + def shield(self) -> ShieldResourceWithRawResponse: + return ShieldResourceWithRawResponse(self._cdn_resources.shield) + + @cached_property + def rules(self) -> RulesResourceWithRawResponse: + return RulesResourceWithRawResponse(self._cdn_resources.rules) + + +class AsyncCDNResourcesResourceWithRawResponse: + def __init__(self, cdn_resources: AsyncCDNResourcesResource) -> None: + self._cdn_resources = cdn_resources + + self.create = async_to_raw_response_wrapper( + cdn_resources.create, + ) + self.update = async_to_raw_response_wrapper( + cdn_resources.update, + ) + self.list = async_to_raw_response_wrapper( + cdn_resources.list, + ) + self.delete = async_to_raw_response_wrapper( + cdn_resources.delete, + ) + self.get = async_to_raw_response_wrapper( + cdn_resources.get, + ) + self.prefetch = async_to_raw_response_wrapper( + cdn_resources.prefetch, + ) + self.prevalidate_ssl_le_certificate = async_to_raw_response_wrapper( + cdn_resources.prevalidate_ssl_le_certificate, + ) + self.purge = async_to_raw_response_wrapper( + cdn_resources.purge, + ) + self.replace = async_to_raw_response_wrapper( + cdn_resources.replace, + ) + + @cached_property + def shield(self) -> AsyncShieldResourceWithRawResponse: + return AsyncShieldResourceWithRawResponse(self._cdn_resources.shield) + + @cached_property + def rules(self) -> AsyncRulesResourceWithRawResponse: + return AsyncRulesResourceWithRawResponse(self._cdn_resources.rules) + + +class CDNResourcesResourceWithStreamingResponse: + def __init__(self, cdn_resources: CDNResourcesResource) -> None: + self._cdn_resources = cdn_resources + + self.create = to_streamed_response_wrapper( + cdn_resources.create, + ) + self.update = to_streamed_response_wrapper( + cdn_resources.update, + ) + self.list = to_streamed_response_wrapper( + cdn_resources.list, + ) + self.delete = to_streamed_response_wrapper( + cdn_resources.delete, + ) + self.get = to_streamed_response_wrapper( + cdn_resources.get, + ) + self.prefetch = to_streamed_response_wrapper( + cdn_resources.prefetch, + ) + self.prevalidate_ssl_le_certificate = to_streamed_response_wrapper( + cdn_resources.prevalidate_ssl_le_certificate, + ) + self.purge = to_streamed_response_wrapper( + cdn_resources.purge, + ) + self.replace = to_streamed_response_wrapper( + cdn_resources.replace, + ) + + @cached_property + def shield(self) -> ShieldResourceWithStreamingResponse: + return ShieldResourceWithStreamingResponse(self._cdn_resources.shield) + + @cached_property + def rules(self) -> RulesResourceWithStreamingResponse: + return RulesResourceWithStreamingResponse(self._cdn_resources.rules) + + +class AsyncCDNResourcesResourceWithStreamingResponse: + def __init__(self, cdn_resources: AsyncCDNResourcesResource) -> None: + self._cdn_resources = cdn_resources + + self.create = async_to_streamed_response_wrapper( + cdn_resources.create, + ) + self.update = async_to_streamed_response_wrapper( + cdn_resources.update, + ) + self.list = async_to_streamed_response_wrapper( + cdn_resources.list, + ) + self.delete = async_to_streamed_response_wrapper( + cdn_resources.delete, + ) + self.get = async_to_streamed_response_wrapper( + cdn_resources.get, + ) + self.prefetch = async_to_streamed_response_wrapper( + cdn_resources.prefetch, + ) + self.prevalidate_ssl_le_certificate = async_to_streamed_response_wrapper( + cdn_resources.prevalidate_ssl_le_certificate, + ) + self.purge = async_to_streamed_response_wrapper( + cdn_resources.purge, + ) + self.replace = async_to_streamed_response_wrapper( + cdn_resources.replace, + ) + + @cached_property + def shield(self) -> AsyncShieldResourceWithStreamingResponse: + return AsyncShieldResourceWithStreamingResponse(self._cdn_resources.shield) + + @cached_property + def rules(self) -> AsyncRulesResourceWithStreamingResponse: + return AsyncRulesResourceWithStreamingResponse(self._cdn_resources.rules) diff --git a/src/gcore/resources/cdn/cdn_resources/rules.py b/src/gcore/resources/cdn/cdn_resources/rules.py new file mode 100644 index 00000000..7c0424d5 --- /dev/null +++ b/src/gcore/resources/cdn/cdn_resources/rules.py @@ -0,0 +1,1003 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cdn.cdn_resources import rule_create_params, rule_update_params, rule_replace_params +from ....types.cdn.cdn_resources.cdn_resource_rule import CDNResourceRule +from ....types.cdn.cdn_resources.rule_list_response import RuleListResponse + +__all__ = ["RulesResource", "AsyncRulesResource"] + + +class RulesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return RulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return RulesResourceWithStreamingResponse(self) + + def create( + self, + resource_id: int, + *, + name: str, + rule: str, + rule_type: int, + active: bool | Omit = omit, + options: rule_create_params.Options | Omit = omit, + origin_group: Optional[int] | Omit = omit, + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResourceRule: + """ + Create rule + + Args: + name: Rule name. + + rule: Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + + rule_type: Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + + active: Enables or disables a rule. + + Possible values: + + - **true** - Rule is active, rule settings are applied. + - **false** - Rule is inactive, rule settings are not applied. + + options: List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + + origin_group: ID of the origin group to which the rule is applied. + + If the origin group is not specified, the rule is applied to the origin group + that the CDN resource is associated with. + + override_origin_protocol: Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + + weight: Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/cdn/resources/{resource_id}/rules", + body=maybe_transform( + { + "name": name, + "rule": rule, + "rule_type": rule_type, + "active": active, + "options": options, + "origin_group": origin_group, + "override_origin_protocol": override_origin_protocol, + "weight": weight, + }, + rule_create_params.RuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResourceRule, + ) + + def update( + self, + rule_id: int, + *, + resource_id: int, + active: bool | Omit = omit, + name: str | Omit = omit, + options: rule_update_params.Options | Omit = omit, + origin_group: Optional[int] | Omit = omit, + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] | Omit = omit, + rule: str | Omit = omit, + rule_type: int | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResourceRule: + """ + Change rule + + Args: + active: Enables or disables a rule. + + Possible values: + + - **true** - Rule is active, rule settings are applied. + - **false** - Rule is inactive, rule settings are not applied. + + name: Rule name. + + options: List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + + origin_group: ID of the origin group to which the rule is applied. + + If the origin group is not specified, the rule is applied to the origin group + that the CDN resource is associated with. + + override_origin_protocol: Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + + rule: Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + + rule_type: Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + + weight: Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/cdn/resources/{resource_id}/rules/{rule_id}", + body=maybe_transform( + { + "active": active, + "name": name, + "options": options, + "origin_group": origin_group, + "override_origin_protocol": override_origin_protocol, + "rule": rule, + "rule_type": rule_type, + "weight": weight, + }, + rule_update_params.RuleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResourceRule, + ) + + def list( + self, + resource_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleListResponse: + """ + Get rules list + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cdn/resources/{resource_id}/rules", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RuleListResponse, + ) + + def delete( + self, + rule_id: int, + *, + resource_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete the rule from the system permanently. + + Notes: + + - **Deactivation Requirement**: Set the `active` attribute to `false` before + deletion. + - **Irreversibility**: This action is irreversible. Once deleted, the rule + cannot be recovered. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cdn/resources/{resource_id}/rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + rule_id: int, + *, + resource_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResourceRule: + """ + Get rule details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cdn/resources/{resource_id}/rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResourceRule, + ) + + def replace( + self, + rule_id: int, + *, + resource_id: int, + rule: str, + rule_type: int, + active: bool | Omit = omit, + name: str | Omit = omit, + options: rule_replace_params.Options | Omit = omit, + origin_group: Optional[int] | Omit = omit, + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResourceRule: + """ + Change rule + + Args: + rule: Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + + rule_type: Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + + active: Enables or disables a rule. + + Possible values: + + - **true** - Rule is active, rule settings are applied. + - **false** - Rule is inactive, rule settings are not applied. + + name: Rule name. + + options: List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + + origin_group: ID of the origin group to which the rule is applied. + + If the origin group is not specified, the rule is applied to the origin group + that the CDN resource is associated with. + + override_origin_protocol: Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + + weight: Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/cdn/resources/{resource_id}/rules/{rule_id}", + body=maybe_transform( + { + "rule": rule, + "rule_type": rule_type, + "active": active, + "name": name, + "options": options, + "origin_group": origin_group, + "override_origin_protocol": override_origin_protocol, + "weight": weight, + }, + rule_replace_params.RuleReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResourceRule, + ) + + +class AsyncRulesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncRulesResourceWithStreamingResponse(self) + + async def create( + self, + resource_id: int, + *, + name: str, + rule: str, + rule_type: int, + active: bool | Omit = omit, + options: rule_create_params.Options | Omit = omit, + origin_group: Optional[int] | Omit = omit, + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResourceRule: + """ + Create rule + + Args: + name: Rule name. + + rule: Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + + rule_type: Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + + active: Enables or disables a rule. + + Possible values: + + - **true** - Rule is active, rule settings are applied. + - **false** - Rule is inactive, rule settings are not applied. + + options: List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + + origin_group: ID of the origin group to which the rule is applied. + + If the origin group is not specified, the rule is applied to the origin group + that the CDN resource is associated with. + + override_origin_protocol: Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + + weight: Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/cdn/resources/{resource_id}/rules", + body=await async_maybe_transform( + { + "name": name, + "rule": rule, + "rule_type": rule_type, + "active": active, + "options": options, + "origin_group": origin_group, + "override_origin_protocol": override_origin_protocol, + "weight": weight, + }, + rule_create_params.RuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResourceRule, + ) + + async def update( + self, + rule_id: int, + *, + resource_id: int, + active: bool | Omit = omit, + name: str | Omit = omit, + options: rule_update_params.Options | Omit = omit, + origin_group: Optional[int] | Omit = omit, + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] | Omit = omit, + rule: str | Omit = omit, + rule_type: int | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResourceRule: + """ + Change rule + + Args: + active: Enables or disables a rule. + + Possible values: + + - **true** - Rule is active, rule settings are applied. + - **false** - Rule is inactive, rule settings are not applied. + + name: Rule name. + + options: List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + + origin_group: ID of the origin group to which the rule is applied. + + If the origin group is not specified, the rule is applied to the origin group + that the CDN resource is associated with. + + override_origin_protocol: Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + + rule: Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + + rule_type: Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + + weight: Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/cdn/resources/{resource_id}/rules/{rule_id}", + body=await async_maybe_transform( + { + "active": active, + "name": name, + "options": options, + "origin_group": origin_group, + "override_origin_protocol": override_origin_protocol, + "rule": rule, + "rule_type": rule_type, + "weight": weight, + }, + rule_update_params.RuleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResourceRule, + ) + + async def list( + self, + resource_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleListResponse: + """ + Get rules list + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cdn/resources/{resource_id}/rules", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RuleListResponse, + ) + + async def delete( + self, + rule_id: int, + *, + resource_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete the rule from the system permanently. + + Notes: + + - **Deactivation Requirement**: Set the `active` attribute to `false` before + deletion. + - **Irreversibility**: This action is irreversible. Once deleted, the rule + cannot be recovered. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cdn/resources/{resource_id}/rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + rule_id: int, + *, + resource_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResourceRule: + """ + Get rule details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cdn/resources/{resource_id}/rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResourceRule, + ) + + async def replace( + self, + rule_id: int, + *, + resource_id: int, + rule: str, + rule_type: int, + active: bool | Omit = omit, + name: str | Omit = omit, + options: rule_replace_params.Options | Omit = omit, + origin_group: Optional[int] | Omit = omit, + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNResourceRule: + """ + Change rule + + Args: + rule: Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + + rule_type: Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + + active: Enables or disables a rule. + + Possible values: + + - **true** - Rule is active, rule settings are applied. + - **false** - Rule is inactive, rule settings are not applied. + + name: Rule name. + + options: List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + + origin_group: ID of the origin group to which the rule is applied. + + If the origin group is not specified, the rule is applied to the origin group + that the CDN resource is associated with. + + override_origin_protocol: Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + + weight: Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/cdn/resources/{resource_id}/rules/{rule_id}", + body=await async_maybe_transform( + { + "rule": rule, + "rule_type": rule_type, + "active": active, + "name": name, + "options": options, + "origin_group": origin_group, + "override_origin_protocol": override_origin_protocol, + "weight": weight, + }, + rule_replace_params.RuleReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNResourceRule, + ) + + +class RulesResourceWithRawResponse: + def __init__(self, rules: RulesResource) -> None: + self._rules = rules + + self.create = to_raw_response_wrapper( + rules.create, + ) + self.update = to_raw_response_wrapper( + rules.update, + ) + self.list = to_raw_response_wrapper( + rules.list, + ) + self.delete = to_raw_response_wrapper( + rules.delete, + ) + self.get = to_raw_response_wrapper( + rules.get, + ) + self.replace = to_raw_response_wrapper( + rules.replace, + ) + + +class AsyncRulesResourceWithRawResponse: + def __init__(self, rules: AsyncRulesResource) -> None: + self._rules = rules + + self.create = async_to_raw_response_wrapper( + rules.create, + ) + self.update = async_to_raw_response_wrapper( + rules.update, + ) + self.list = async_to_raw_response_wrapper( + rules.list, + ) + self.delete = async_to_raw_response_wrapper( + rules.delete, + ) + self.get = async_to_raw_response_wrapper( + rules.get, + ) + self.replace = async_to_raw_response_wrapper( + rules.replace, + ) + + +class RulesResourceWithStreamingResponse: + def __init__(self, rules: RulesResource) -> None: + self._rules = rules + + self.create = to_streamed_response_wrapper( + rules.create, + ) + self.update = to_streamed_response_wrapper( + rules.update, + ) + self.list = to_streamed_response_wrapper( + rules.list, + ) + self.delete = to_streamed_response_wrapper( + rules.delete, + ) + self.get = to_streamed_response_wrapper( + rules.get, + ) + self.replace = to_streamed_response_wrapper( + rules.replace, + ) + + +class AsyncRulesResourceWithStreamingResponse: + def __init__(self, rules: AsyncRulesResource) -> None: + self._rules = rules + + self.create = async_to_streamed_response_wrapper( + rules.create, + ) + self.update = async_to_streamed_response_wrapper( + rules.update, + ) + self.list = async_to_streamed_response_wrapper( + rules.list, + ) + self.delete = async_to_streamed_response_wrapper( + rules.delete, + ) + self.get = async_to_streamed_response_wrapper( + rules.get, + ) + self.replace = async_to_streamed_response_wrapper( + rules.replace, + ) diff --git a/src/gcore/resources/cdn/cdn_resources/shield.py b/src/gcore/resources/cdn/cdn_resources/shield.py new file mode 100644 index 00000000..27c2bf2a --- /dev/null +++ b/src/gcore/resources/cdn/cdn_resources/shield.py @@ -0,0 +1,251 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cdn.cdn_resources import shield_replace_params +from ....types.cdn.cdn_resources.origin_shielding import OriginShielding + +__all__ = ["ShieldResource", "AsyncShieldResource"] + + +class ShieldResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ShieldResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ShieldResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ShieldResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ShieldResourceWithStreamingResponse(self) + + def get( + self, + resource_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginShielding: + """ + Get information about origin shielding. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cdn/resources/{resource_id}/shielding_v2", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OriginShielding, + ) + + def replace( + self, + resource_id: int, + *, + shielding_pop: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Change origin shielding settings or disabled origin shielding. + + Args: + shielding_pop: Shielding location ID. + + If origin shielding is disabled, the parameter value is **null**. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/cdn/resources/{resource_id}/shielding_v2", + body=maybe_transform({"shielding_pop": shielding_pop}, shield_replace_params.ShieldReplaceParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncShieldResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncShieldResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncShieldResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncShieldResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncShieldResourceWithStreamingResponse(self) + + async def get( + self, + resource_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginShielding: + """ + Get information about origin shielding. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cdn/resources/{resource_id}/shielding_v2", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OriginShielding, + ) + + async def replace( + self, + resource_id: int, + *, + shielding_pop: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Change origin shielding settings or disabled origin shielding. + + Args: + shielding_pop: Shielding location ID. + + If origin shielding is disabled, the parameter value is **null**. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/cdn/resources/{resource_id}/shielding_v2", + body=await async_maybe_transform( + {"shielding_pop": shielding_pop}, shield_replace_params.ShieldReplaceParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class ShieldResourceWithRawResponse: + def __init__(self, shield: ShieldResource) -> None: + self._shield = shield + + self.get = to_raw_response_wrapper( + shield.get, + ) + self.replace = to_raw_response_wrapper( + shield.replace, + ) + + +class AsyncShieldResourceWithRawResponse: + def __init__(self, shield: AsyncShieldResource) -> None: + self._shield = shield + + self.get = async_to_raw_response_wrapper( + shield.get, + ) + self.replace = async_to_raw_response_wrapper( + shield.replace, + ) + + +class ShieldResourceWithStreamingResponse: + def __init__(self, shield: ShieldResource) -> None: + self._shield = shield + + self.get = to_streamed_response_wrapper( + shield.get, + ) + self.replace = to_streamed_response_wrapper( + shield.replace, + ) + + +class AsyncShieldResourceWithStreamingResponse: + def __init__(self, shield: AsyncShieldResource) -> None: + self._shield = shield + + self.get = async_to_streamed_response_wrapper( + shield.get, + ) + self.replace = async_to_streamed_response_wrapper( + shield.replace, + ) diff --git a/src/gcore/resources/cdn/certificates.py b/src/gcore/resources/cdn/certificates.py new file mode 100644 index 00000000..5b299f13 --- /dev/null +++ b/src/gcore/resources/cdn/certificates.py @@ -0,0 +1,1038 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import overload + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import required_args, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cdn import ( + certificate_list_params, + certificate_create_params, + certificate_replace_params, + certificate_get_status_params, +) +from ..._base_client import make_request_options +from ...types.cdn.ssl_detail import SslDetail +from ...types.cdn.ssl_detail_list import SslDetailList +from ...types.cdn.ssl_request_status import SslRequestStatus + +__all__ = ["CertificatesResource", "AsyncCertificatesResource"] + + +class CertificatesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CertificatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return CertificatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CertificatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return CertificatesResourceWithStreamingResponse(self) + + @overload + def create( + self, + *, + name: str, + ssl_certificate: str, + ssl_private_key: str, + validate_root_ca: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Add an SSL certificate for content delivery over HTTPS protocol. + + Enter all strings of the certificate(s) and the private key into one string + parameter. Each certificate and the private key in chain should be separated by + the "\n" symbol, as shown in the example. + + Additionally, you can add a Let's Encrypt certificate. In this case, certificate + and private key will be generated automatically after attaching this certificate + to your CDN resource. + + Args: + name: SSL certificate name. + + It must be unique. + + ssl_certificate: Public part of the SSL certificate. + + All chain of the SSL certificate should be added. + + ssl_private_key: Private key of the SSL certificate. + + validate_root_ca: Defines whether to check the SSL certificate for a signature from a trusted + certificate authority. + + Possible values: + + - **true** - SSL certificate must be verified to be signed by a trusted + certificate authority. + - **false** - SSL certificate will not be verified to be signed by a trusted + certificate authority. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + automated: bool, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Add an SSL certificate for content delivery over HTTPS protocol. + + Enter all strings of the certificate(s) and the private key into one string + parameter. Each certificate and the private key in chain should be separated by + the "\n" symbol, as shown in the example. + + Additionally, you can add a Let's Encrypt certificate. In this case, certificate + and private key will be generated automatically after attaching this certificate + to your CDN resource. + + Args: + automated: Must be **true** to issue certificate automatically. + + name: SSL certificate name. It must be unique. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["name", "ssl_certificate", "ssl_private_key"], ["automated", "name"]) + def create( + self, + *, + name: str, + ssl_certificate: str | Omit = omit, + ssl_private_key: str | Omit = omit, + validate_root_ca: bool | Omit = omit, + automated: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + "/cdn/sslData", + body=maybe_transform( + { + "name": name, + "ssl_certificate": ssl_certificate, + "ssl_private_key": ssl_private_key, + "validate_root_ca": validate_root_ca, + "automated": automated, + }, + certificate_create_params.CertificateCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + *, + automated: bool | Omit = omit, + resource_id: int | Omit = omit, + validity_not_after_lte: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SslDetailList: + """ + Get information about SSL certificates. + + Args: + automated: How the SSL certificate was issued. + + Possible values: + + - **true** – Certificate was issued automatically. + - **false** – Certificate was added by a user. + + resource_id: CDN resource ID for which certificates are requested. + + validity_not_after_lte: Date and time when the certificate become untrusted (ISO 8601/RFC 3339 format, + UTC.) + + Response will contain only certificates valid until the specified time. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/sslData", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "automated": automated, + "resource_id": resource_id, + "validity_not_after_lte": validity_not_after_lte, + }, + certificate_list_params.CertificateListParams, + ), + ), + cast_to=SslDetailList, + ) + + def delete( + self, + ssl_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete SSL certificate + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cdn/sslData/{ssl_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def force_retry( + self, + cert_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Force retry issuance of Let's Encrypt certificate if the previous attempt was + failed. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/cdn/sslData/{cert_id}/force-retry", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + ssl_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SslDetail: + """ + Get SSL certificate details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cdn/sslData/{ssl_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SslDetail, + ) + + def get_status( + self, + cert_id: int, + *, + exclude: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SslRequestStatus: + """ + Get details about the latest Let's Encrypt certificate issuing attempt for the + CDN resource. Returns attempts in all statuses. + + Args: + exclude: Listed fields will be excluded from the response. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cdn/sslData/{cert_id}/status", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"exclude": exclude}, certificate_get_status_params.CertificateGetStatusParams), + ), + cast_to=SslRequestStatus, + ) + + def renew( + self, + cert_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Renew free Let's Encrypt certificate for the CDN resource. + + It can take up to + fifteen minutes. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/cdn/sslData/{cert_id}/renew", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def replace( + self, + ssl_id: int, + *, + name: str, + ssl_certificate: str, + ssl_private_key: str, + validate_root_ca: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SslDetail: + """ + Change SSL certificate + + Args: + name: SSL certificate name. + + It must be unique. + + ssl_certificate: Public part of the SSL certificate. + + All chain of the SSL certificate should be added. + + ssl_private_key: Private key of the SSL certificate. + + validate_root_ca: Defines whether to check the SSL certificate for a signature from a trusted + certificate authority. + + Possible values: + + - **true** - SSL certificate must be verified to be signed by a trusted + certificate authority. + - **false** - SSL certificate will not be verified to be signed by a trusted + certificate authority. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/cdn/sslData/{ssl_id}", + body=maybe_transform( + { + "name": name, + "ssl_certificate": ssl_certificate, + "ssl_private_key": ssl_private_key, + "validate_root_ca": validate_root_ca, + }, + certificate_replace_params.CertificateReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SslDetail, + ) + + +class AsyncCertificatesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCertificatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncCertificatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCertificatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncCertificatesResourceWithStreamingResponse(self) + + @overload + async def create( + self, + *, + name: str, + ssl_certificate: str, + ssl_private_key: str, + validate_root_ca: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Add an SSL certificate for content delivery over HTTPS protocol. + + Enter all strings of the certificate(s) and the private key into one string + parameter. Each certificate and the private key in chain should be separated by + the "\n" symbol, as shown in the example. + + Additionally, you can add a Let's Encrypt certificate. In this case, certificate + and private key will be generated automatically after attaching this certificate + to your CDN resource. + + Args: + name: SSL certificate name. + + It must be unique. + + ssl_certificate: Public part of the SSL certificate. + + All chain of the SSL certificate should be added. + + ssl_private_key: Private key of the SSL certificate. + + validate_root_ca: Defines whether to check the SSL certificate for a signature from a trusted + certificate authority. + + Possible values: + + - **true** - SSL certificate must be verified to be signed by a trusted + certificate authority. + - **false** - SSL certificate will not be verified to be signed by a trusted + certificate authority. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + automated: bool, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Add an SSL certificate for content delivery over HTTPS protocol. + + Enter all strings of the certificate(s) and the private key into one string + parameter. Each certificate and the private key in chain should be separated by + the "\n" symbol, as shown in the example. + + Additionally, you can add a Let's Encrypt certificate. In this case, certificate + and private key will be generated automatically after attaching this certificate + to your CDN resource. + + Args: + automated: Must be **true** to issue certificate automatically. + + name: SSL certificate name. It must be unique. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["name", "ssl_certificate", "ssl_private_key"], ["automated", "name"]) + async def create( + self, + *, + name: str, + ssl_certificate: str | Omit = omit, + ssl_private_key: str | Omit = omit, + validate_root_ca: bool | Omit = omit, + automated: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + "/cdn/sslData", + body=await async_maybe_transform( + { + "name": name, + "ssl_certificate": ssl_certificate, + "ssl_private_key": ssl_private_key, + "validate_root_ca": validate_root_ca, + "automated": automated, + }, + certificate_create_params.CertificateCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def list( + self, + *, + automated: bool | Omit = omit, + resource_id: int | Omit = omit, + validity_not_after_lte: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SslDetailList: + """ + Get information about SSL certificates. + + Args: + automated: How the SSL certificate was issued. + + Possible values: + + - **true** – Certificate was issued automatically. + - **false** – Certificate was added by a user. + + resource_id: CDN resource ID for which certificates are requested. + + validity_not_after_lte: Date and time when the certificate become untrusted (ISO 8601/RFC 3339 format, + UTC.) + + Response will contain only certificates valid until the specified time. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/sslData", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "automated": automated, + "resource_id": resource_id, + "validity_not_after_lte": validity_not_after_lte, + }, + certificate_list_params.CertificateListParams, + ), + ), + cast_to=SslDetailList, + ) + + async def delete( + self, + ssl_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete SSL certificate + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cdn/sslData/{ssl_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def force_retry( + self, + cert_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Force retry issuance of Let's Encrypt certificate if the previous attempt was + failed. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/cdn/sslData/{cert_id}/force-retry", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + ssl_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SslDetail: + """ + Get SSL certificate details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cdn/sslData/{ssl_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SslDetail, + ) + + async def get_status( + self, + cert_id: int, + *, + exclude: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SslRequestStatus: + """ + Get details about the latest Let's Encrypt certificate issuing attempt for the + CDN resource. Returns attempts in all statuses. + + Args: + exclude: Listed fields will be excluded from the response. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cdn/sslData/{cert_id}/status", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"exclude": exclude}, certificate_get_status_params.CertificateGetStatusParams + ), + ), + cast_to=SslRequestStatus, + ) + + async def renew( + self, + cert_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Renew free Let's Encrypt certificate for the CDN resource. + + It can take up to + fifteen minutes. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/cdn/sslData/{cert_id}/renew", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def replace( + self, + ssl_id: int, + *, + name: str, + ssl_certificate: str, + ssl_private_key: str, + validate_root_ca: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SslDetail: + """ + Change SSL certificate + + Args: + name: SSL certificate name. + + It must be unique. + + ssl_certificate: Public part of the SSL certificate. + + All chain of the SSL certificate should be added. + + ssl_private_key: Private key of the SSL certificate. + + validate_root_ca: Defines whether to check the SSL certificate for a signature from a trusted + certificate authority. + + Possible values: + + - **true** - SSL certificate must be verified to be signed by a trusted + certificate authority. + - **false** - SSL certificate will not be verified to be signed by a trusted + certificate authority. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/cdn/sslData/{ssl_id}", + body=await async_maybe_transform( + { + "name": name, + "ssl_certificate": ssl_certificate, + "ssl_private_key": ssl_private_key, + "validate_root_ca": validate_root_ca, + }, + certificate_replace_params.CertificateReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SslDetail, + ) + + +class CertificatesResourceWithRawResponse: + def __init__(self, certificates: CertificatesResource) -> None: + self._certificates = certificates + + self.create = to_raw_response_wrapper( + certificates.create, + ) + self.list = to_raw_response_wrapper( + certificates.list, + ) + self.delete = to_raw_response_wrapper( + certificates.delete, + ) + self.force_retry = to_raw_response_wrapper( + certificates.force_retry, + ) + self.get = to_raw_response_wrapper( + certificates.get, + ) + self.get_status = to_raw_response_wrapper( + certificates.get_status, + ) + self.renew = to_raw_response_wrapper( + certificates.renew, + ) + self.replace = to_raw_response_wrapper( + certificates.replace, + ) + + +class AsyncCertificatesResourceWithRawResponse: + def __init__(self, certificates: AsyncCertificatesResource) -> None: + self._certificates = certificates + + self.create = async_to_raw_response_wrapper( + certificates.create, + ) + self.list = async_to_raw_response_wrapper( + certificates.list, + ) + self.delete = async_to_raw_response_wrapper( + certificates.delete, + ) + self.force_retry = async_to_raw_response_wrapper( + certificates.force_retry, + ) + self.get = async_to_raw_response_wrapper( + certificates.get, + ) + self.get_status = async_to_raw_response_wrapper( + certificates.get_status, + ) + self.renew = async_to_raw_response_wrapper( + certificates.renew, + ) + self.replace = async_to_raw_response_wrapper( + certificates.replace, + ) + + +class CertificatesResourceWithStreamingResponse: + def __init__(self, certificates: CertificatesResource) -> None: + self._certificates = certificates + + self.create = to_streamed_response_wrapper( + certificates.create, + ) + self.list = to_streamed_response_wrapper( + certificates.list, + ) + self.delete = to_streamed_response_wrapper( + certificates.delete, + ) + self.force_retry = to_streamed_response_wrapper( + certificates.force_retry, + ) + self.get = to_streamed_response_wrapper( + certificates.get, + ) + self.get_status = to_streamed_response_wrapper( + certificates.get_status, + ) + self.renew = to_streamed_response_wrapper( + certificates.renew, + ) + self.replace = to_streamed_response_wrapper( + certificates.replace, + ) + + +class AsyncCertificatesResourceWithStreamingResponse: + def __init__(self, certificates: AsyncCertificatesResource) -> None: + self._certificates = certificates + + self.create = async_to_streamed_response_wrapper( + certificates.create, + ) + self.list = async_to_streamed_response_wrapper( + certificates.list, + ) + self.delete = async_to_streamed_response_wrapper( + certificates.delete, + ) + self.force_retry = async_to_streamed_response_wrapper( + certificates.force_retry, + ) + self.get = async_to_streamed_response_wrapper( + certificates.get, + ) + self.get_status = async_to_streamed_response_wrapper( + certificates.get_status, + ) + self.renew = async_to_streamed_response_wrapper( + certificates.renew, + ) + self.replace = async_to_streamed_response_wrapper( + certificates.replace, + ) diff --git a/src/gcore/resources/cdn/ip_ranges.py b/src/gcore/resources/cdn/ip_ranges.py new file mode 100644 index 00000000..ee39f4a9 --- /dev/null +++ b/src/gcore/resources/cdn/ip_ranges.py @@ -0,0 +1,312 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cdn import ip_range_list_params, ip_range_list_ips_params +from ..._base_client import make_request_options +from ...types.cdn.public_ip_list import PublicIPList +from ...types.cdn.public_network_list import PublicNetworkList + +__all__ = ["IPRangesResource", "AsyncIPRangesResource"] + + +class IPRangesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> IPRangesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return IPRangesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> IPRangesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return IPRangesResourceWithStreamingResponse(self) + + def list( + self, + *, + format: Literal["json", "plain"] | Omit = omit, + accept: Literal["application/json", "text/plain"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PublicNetworkList: + """ + Get all CDN networks that can be used to pull content from your origin. + + This list is updated periodically. If you want to use network from this list to + configure IP ACL on your origin, you need to independently monitor its + relevance. We recommend using a script for automatically update IP ACL. + + This request does not require authorization. + + Args: + format: Optional format override. When set, this takes precedence over the `Accept` + header. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = { + **strip_not_given({"Accept": str(accept) if is_given(accept) else not_given}), + **(extra_headers or {}), + } + return self._get( + "/cdn/public-net-list", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"format": format}, ip_range_list_params.IPRangeListParams), + ), + cast_to=PublicNetworkList, + ) + + def list_ips( + self, + *, + format: Literal["json", "plain"] | Omit = omit, + accept: Literal["application/json", "text/plain"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PublicIPList: + """ + Get all IP addresses of CDN servers that can be used to pull content from your + origin. + + This list is updated periodically. If you want to use IP from this list to + configure IP ACL in your origin, you need to independently monitor its + relevance. We recommend using a script to automatically update IP ACL. + + This request does not require authorization. + + Args: + format: Optional format override. When set, this takes precedence over the `Accept` + header. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = { + **strip_not_given({"Accept": str(accept) if is_given(accept) else not_given}), + **(extra_headers or {}), + } + return self._get( + "/cdn/public-ip-list", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"format": format}, ip_range_list_ips_params.IPRangeListIPsParams), + ), + cast_to=PublicIPList, + ) + + +class AsyncIPRangesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncIPRangesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncIPRangesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncIPRangesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncIPRangesResourceWithStreamingResponse(self) + + async def list( + self, + *, + format: Literal["json", "plain"] | Omit = omit, + accept: Literal["application/json", "text/plain"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PublicNetworkList: + """ + Get all CDN networks that can be used to pull content from your origin. + + This list is updated periodically. If you want to use network from this list to + configure IP ACL on your origin, you need to independently monitor its + relevance. We recommend using a script for automatically update IP ACL. + + This request does not require authorization. + + Args: + format: Optional format override. When set, this takes precedence over the `Accept` + header. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = { + **strip_not_given({"Accept": str(accept) if is_given(accept) else not_given}), + **(extra_headers or {}), + } + return await self._get( + "/cdn/public-net-list", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"format": format}, ip_range_list_params.IPRangeListParams), + ), + cast_to=PublicNetworkList, + ) + + async def list_ips( + self, + *, + format: Literal["json", "plain"] | Omit = omit, + accept: Literal["application/json", "text/plain"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PublicIPList: + """ + Get all IP addresses of CDN servers that can be used to pull content from your + origin. + + This list is updated periodically. If you want to use IP from this list to + configure IP ACL in your origin, you need to independently monitor its + relevance. We recommend using a script to automatically update IP ACL. + + This request does not require authorization. + + Args: + format: Optional format override. When set, this takes precedence over the `Accept` + header. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = { + **strip_not_given({"Accept": str(accept) if is_given(accept) else not_given}), + **(extra_headers or {}), + } + return await self._get( + "/cdn/public-ip-list", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"format": format}, ip_range_list_ips_params.IPRangeListIPsParams), + ), + cast_to=PublicIPList, + ) + + +class IPRangesResourceWithRawResponse: + def __init__(self, ip_ranges: IPRangesResource) -> None: + self._ip_ranges = ip_ranges + + self.list = to_raw_response_wrapper( + ip_ranges.list, + ) + self.list_ips = to_raw_response_wrapper( + ip_ranges.list_ips, + ) + + +class AsyncIPRangesResourceWithRawResponse: + def __init__(self, ip_ranges: AsyncIPRangesResource) -> None: + self._ip_ranges = ip_ranges + + self.list = async_to_raw_response_wrapper( + ip_ranges.list, + ) + self.list_ips = async_to_raw_response_wrapper( + ip_ranges.list_ips, + ) + + +class IPRangesResourceWithStreamingResponse: + def __init__(self, ip_ranges: IPRangesResource) -> None: + self._ip_ranges = ip_ranges + + self.list = to_streamed_response_wrapper( + ip_ranges.list, + ) + self.list_ips = to_streamed_response_wrapper( + ip_ranges.list_ips, + ) + + +class AsyncIPRangesResourceWithStreamingResponse: + def __init__(self, ip_ranges: AsyncIPRangesResource) -> None: + self._ip_ranges = ip_ranges + + self.list = async_to_streamed_response_wrapper( + ip_ranges.list, + ) + self.list_ips = async_to_streamed_response_wrapper( + ip_ranges.list_ips, + ) diff --git a/src/gcore/resources/cdn/logs.py b/src/gcore/resources/cdn/logs.py new file mode 100644 index 00000000..4791a254 --- /dev/null +++ b/src/gcore/resources/cdn/logs.py @@ -0,0 +1,1384 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + BinaryAPIResponse, + AsyncBinaryAPIResponse, + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + to_custom_raw_response_wrapper, + async_to_streamed_response_wrapper, + to_custom_streamed_response_wrapper, + async_to_custom_raw_response_wrapper, + async_to_custom_streamed_response_wrapper, +) +from ...types.cdn import log_list_params, log_download_params +from ...pagination import SyncOffsetPageCDNLogs, AsyncOffsetPageCDNLogs +from ..._base_client import AsyncPaginator, make_request_options +from ...types.cdn.cdn_log_entry import Data + +__all__ = ["LogsResource", "AsyncLogsResource"] + + +class LogsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> LogsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return LogsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> LogsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return LogsResourceWithStreamingResponse(self) + + def list( + self, + *, + from_: str, + to: str, + cache_status_eq: str | Omit = omit, + cache_status_in: str | Omit = omit, + cache_status_ne: str | Omit = omit, + cache_status_not_in: str | Omit = omit, + client_ip_eq: str | Omit = omit, + client_ip_in: str | Omit = omit, + client_ip_ne: str | Omit = omit, + client_ip_not_in: str | Omit = omit, + cname_contains: str | Omit = omit, + cname_eq: str | Omit = omit, + cname_in: str | Omit = omit, + cname_ne: str | Omit = omit, + cname_not_in: str | Omit = omit, + datacenter_eq: str | Omit = omit, + datacenter_in: str | Omit = omit, + datacenter_ne: str | Omit = omit, + datacenter_not_in: str | Omit = omit, + fields: str | Omit = omit, + limit: int | Omit = omit, + method_eq: str | Omit = omit, + method_in: str | Omit = omit, + method_ne: str | Omit = omit, + method_not_in: str | Omit = omit, + offset: int | Omit = omit, + ordering: str | Omit = omit, + resource_id_eq: int | Omit = omit, + resource_id_gt: int | Omit = omit, + resource_id_gte: int | Omit = omit, + resource_id_in: str | Omit = omit, + resource_id_lt: int | Omit = omit, + resource_id_lte: int | Omit = omit, + resource_id_ne: int | Omit = omit, + resource_id_not_in: str | Omit = omit, + size_eq: int | Omit = omit, + size_gt: int | Omit = omit, + size_gte: int | Omit = omit, + size_in: str | Omit = omit, + size_lt: int | Omit = omit, + size_lte: int | Omit = omit, + size_ne: int | Omit = omit, + size_not_in: str | Omit = omit, + status_eq: int | Omit = omit, + status_gt: int | Omit = omit, + status_gte: int | Omit = omit, + status_in: str | Omit = omit, + status_lt: int | Omit = omit, + status_lte: int | Omit = omit, + status_ne: int | Omit = omit, + status_not_in: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPageCDNLogs[Data]: + """ + Get CDN logs for up to 3 days starting today. + + You can filter logs using query parameters by client IP, CDN resource, date, + path and etc. + + To filter the CDN logs by 2xx status codes, use: + + - &`status__gte`=200&`status__lt`=300 + + Args: + from_: Start date and time of the requested time period (ISO 8601/RFC 3339 format, + UTC.) + + Difference between "from" and "to" cannot exceed 6 hours. + + Examples: + + - &from=2021-06-14T00:00:00Z + - &from=2021-06-14T00:00:00.000Z + + to: End date and time of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + Difference between "from" and "to" cannot exceed 6 hours. + + Examples: + + - &to=2021-06-15T00:00:00Z + - &to=2021-06-15T00:00:00.000Z + + cache_status_eq: Caching status. Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', + 'PENDING', 'UPDATING', 'REVALIDATED', 'HIT', '-'. + + cache_status_in: List of caching statuses. Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', + 'PENDING', 'UPDATING', 'REVALIDATED', 'HIT', '-'. Values should be separated by + a comma. + + cache_status_ne: Caching status not equal to the specified value. Possible values: 'MISS', + 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', 'REVALIDATED', 'HIT', '-'. + + cache_status_not_in: + List of caching statuses not equal to the specified values. Possible values: + 'MISS', 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', 'REVALIDATED', + 'HIT', '-'. Values should be separated by a comma. + + client_ip_eq: IP address of the client who sent the request. + + client_ip_in: List of IP addresses of the clients who sent the request. + + client_ip_ne: IP address of the client who did not send the request. + + client_ip_not_in: List of IP addresses of the clients who did not send the request. + + cname_contains: Part of the custom domain of the requested CDN resource. Minimum length is 3 + characters. + + cname_eq: Custom domain of the requested CDN resource. + + cname_in: List of custom domains of the requested CDN resource. Values should be separated + by a comma. + + cname_ne: Custom domain of the requested CDN resource not equal to the specified value. + + cname_not_in: List of custom domains of the requested CDN resource not equal to the specified + values. Values should be separated by a comma. + + datacenter_eq: Data center where request was processed. + + datacenter_in: List of data centers where request was processed. Values should be separated by + a comma. + + datacenter_ne: Data center where request was not processed. + + datacenter_not_in: List of data centers where request was not processed. Values should be separated + by a comma. + + fields: A comma-separated list of returned fields. + + Supported fields are presented in the responses section. + + Example: + + - &fields=timestamp,path,status + + limit: Maximum number of log records in the response. + + method_eq: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. + + method_in: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. Values should be separated by a + comma. + + method_ne: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. + + method_not_in: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. Values should be separated by a + comma. + + offset: Number of log records to skip starting from the beginning of the requested + period. + + ordering: Sorting rules. + + Possible values: + + - **method** - Request HTTP method. + - **`client_ip`** - IP address of the client who sent the request. + - **status** - Status code in the response. + - **size** - Response size in bytes. + - **cname** - Custom domain of the requested resource. + - **`resource_id`** - ID of the requested CDN resource. + - **`cache_status`** - Caching status. + - **datacenter** - Data center where request was processed. + - **timestamp** - Date and time when the request was made. + + Parameter may have multiple values separated by a comma. + + By default, ascending sorting is applied. To sort in descending order, add '-' + prefix. + + Example: + + - &ordering=-timestamp,status + + resource_id_eq: ID of the requested CDN resource equal to the specified value. + + resource_id_gt: ID of the requested CDN resource greater than the specified value. + + resource_id_gte: ID of the requested CDN resource greater than or equal to the specified value. + + resource_id_in: List of IDs of the requested CDN resource. Values should be separated by a + comma. + + resource_id_lt: ID of the requested CDN resource less than the specified value. + + resource_id_lte: ID of the requested CDN resource less than or equal to the specified value. + + resource_id_ne: ID of the requested CDN resource not equal to the specified value. + + resource_id_not_in: List of IDs of the requested CDN resource not equal to the specified values. + Values should be separated by a comma. + + size_eq: Response size in bytes equal to the specified value. + + size_gt: Response size in bytes greater than the specified value. + + size_gte: Response size in bytes greater than or equal to the specified value. + + size_in: List of response sizes in bytes. Values should be separated by a comma. + + size_lt: Response size in bytes less than the specified value. + + size_lte: Response size in bytes less than or equal to the specified value. + + size_ne: Response size in bytes not equal to the specified value. + + size_not_in: List of response sizes in bytes not equal to the specified values. Values should + be separated by + + status_eq: Status code in the response equal to the specified value. + + status_gt: Status code in the response greater than the specified value. + + status_gte: Status code in the response greater than or equal to the specified value. + + status_in: List of status codes in the response. Values should be separated by a comma. + + status_lt: Status code in the response less than the specified value. + + status_lte: Status code in the response less than or equal to the specified value. + + status_ne: Status code in the response not equal to the specified value. + + status_not_in: List of status codes not in the response. Values should be separated by a comma. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cdn/advanced/v1/logs", + page=SyncOffsetPageCDNLogs[Data], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "to": to, + "cache_status_eq": cache_status_eq, + "cache_status_in": cache_status_in, + "cache_status_ne": cache_status_ne, + "cache_status_not_in": cache_status_not_in, + "client_ip_eq": client_ip_eq, + "client_ip_in": client_ip_in, + "client_ip_ne": client_ip_ne, + "client_ip_not_in": client_ip_not_in, + "cname_contains": cname_contains, + "cname_eq": cname_eq, + "cname_in": cname_in, + "cname_ne": cname_ne, + "cname_not_in": cname_not_in, + "datacenter_eq": datacenter_eq, + "datacenter_in": datacenter_in, + "datacenter_ne": datacenter_ne, + "datacenter_not_in": datacenter_not_in, + "fields": fields, + "limit": limit, + "method_eq": method_eq, + "method_in": method_in, + "method_ne": method_ne, + "method_not_in": method_not_in, + "offset": offset, + "ordering": ordering, + "resource_id_eq": resource_id_eq, + "resource_id_gt": resource_id_gt, + "resource_id_gte": resource_id_gte, + "resource_id_in": resource_id_in, + "resource_id_lt": resource_id_lt, + "resource_id_lte": resource_id_lte, + "resource_id_ne": resource_id_ne, + "resource_id_not_in": resource_id_not_in, + "size_eq": size_eq, + "size_gt": size_gt, + "size_gte": size_gte, + "size_in": size_in, + "size_lt": size_lt, + "size_lte": size_lte, + "size_ne": size_ne, + "size_not_in": size_not_in, + "status_eq": status_eq, + "status_gt": status_gt, + "status_gte": status_gte, + "status_in": status_in, + "status_lt": status_lt, + "status_lte": status_lte, + "status_ne": status_ne, + "status_not_in": status_not_in, + }, + log_list_params.LogListParams, + ), + ), + model=Data, + ) + + def download( + self, + *, + format: str, + from_: str, + to: str, + cache_status_eq: str | Omit = omit, + cache_status_in: str | Omit = omit, + cache_status_ne: str | Omit = omit, + cache_status_not_in: str | Omit = omit, + client_ip_eq: str | Omit = omit, + client_ip_in: str | Omit = omit, + client_ip_ne: str | Omit = omit, + client_ip_not_in: str | Omit = omit, + cname_contains: str | Omit = omit, + cname_eq: str | Omit = omit, + cname_in: str | Omit = omit, + cname_ne: str | Omit = omit, + cname_not_in: str | Omit = omit, + datacenter_eq: str | Omit = omit, + datacenter_in: str | Omit = omit, + datacenter_ne: str | Omit = omit, + datacenter_not_in: str | Omit = omit, + fields: str | Omit = omit, + limit: int | Omit = omit, + method_eq: str | Omit = omit, + method_in: str | Omit = omit, + method_ne: str | Omit = omit, + method_not_in: str | Omit = omit, + offset: int | Omit = omit, + resource_id_eq: int | Omit = omit, + resource_id_gt: int | Omit = omit, + resource_id_gte: int | Omit = omit, + resource_id_in: str | Omit = omit, + resource_id_lt: int | Omit = omit, + resource_id_lte: int | Omit = omit, + resource_id_ne: int | Omit = omit, + resource_id_not_in: str | Omit = omit, + size_eq: int | Omit = omit, + size_gt: int | Omit = omit, + size_gte: int | Omit = omit, + size_in: str | Omit = omit, + size_lt: int | Omit = omit, + size_lte: int | Omit = omit, + size_ne: int | Omit = omit, + size_not_in: str | Omit = omit, + sort: str | Omit = omit, + status_eq: int | Omit = omit, + status_gt: int | Omit = omit, + status_gte: int | Omit = omit, + status_in: str | Omit = omit, + status_lt: int | Omit = omit, + status_lte: int | Omit = omit, + status_ne: int | Omit = omit, + status_not_in: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BinaryAPIResponse: + """ + Download CDN logs for up to 3 days starting today. + + You can filter logs using query params by client IP, CDN resource, date, path + and etc. + + Args: + format: Output format. + + Possible values: + + - csv + - tsv + + from_: Start date and time of the requested time period (ISO 8601/RFC 3339 format, + UTC.) + + Difference between "from" and "to" cannot exceed 6 hours. + + Examples: + + - &from=2021-06-14T00:00:00Z + - &from=2021-06-14T00:00:00.000Z + + to: End date and time of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + Difference between "from" and "to" cannot exceed 6 hours. + + Examples: + + - &to=2021-06-15T00:00:00Z + - &to=2021-06-15T00:00:00.000Z + + cache_status_eq: Caching status. Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', + 'PENDING', 'UPDATING', 'REVALIDATED', 'HIT', '-'. + + cache_status_in: List of caching statuses. Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', + 'PENDING', 'UPDATING', 'REVALIDATED', 'HIT', '-'. Values should be separated by + a comma. + + cache_status_ne: Caching status not equal to the specified value. Possible values: 'MISS', + 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', 'REVALIDATED', 'HIT', '-'. + + cache_status_not_in: + List of caching statuses not equal to the specified values. Possible values: + 'MISS', 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', 'REVALIDATED', + 'HIT', '-'. Values should be separated by a comma. + + client_ip_eq: IP address of the client who sent the request. + + client_ip_in: List of IP addresses of the clients who sent the request. + + client_ip_ne: IP address of the client who did not send the request. + + client_ip_not_in: List of IP addresses of the clients who did not send the request. + + cname_contains: Part of the custom domain of the requested CDN resource. Minimum length is 3 + characters. + + cname_eq: Custom domain of the requested CDN resource. + + cname_in: List of custom domains of the requested CDN resource. Values should be separated + by a comma. + + cname_ne: Custom domain of the requested CDN resource not equal to the specified value. + + cname_not_in: List of custom domains of the requested CDN resource not equal to the specified + values. Values should be separated by a comma. + + datacenter_eq: Data center where request was processed. + + datacenter_in: List of data centers where request was processed. Values should be separated by + a comma. + + datacenter_ne: Data center where request was not processed. + + datacenter_not_in: List of data centers where request was not processed. Values should be separated + by a comma. + + fields: A comma-separated list of returned fields. + + Supported fields are presented in the responses section. + + Example: + + - &fields=timestamp,path,status + + limit: Maximum number of log records in the response. + + method_eq: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. + + method_in: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. Values should be separated by a + comma. + + method_ne: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. + + method_not_in: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. Values should be separated by a + comma. + + offset: Number of log records to skip starting from the beginning of the requested + period. + + resource_id_eq: ID of the requested CDN resource equal to the specified value. + + resource_id_gt: ID of the requested CDN resource greater than the specified value. + + resource_id_gte: ID of the requested CDN resource greater than or equal to the specified value. + + resource_id_in: List of IDs of the requested CDN resource. Values should be separated by a + comma. + + resource_id_lt: ID of the requested CDN resource less than the specified value. + + resource_id_lte: ID of the requested CDN resource less than or equal to the specified value. + + resource_id_ne: ID of the requested CDN resource not equal to the specified value. + + resource_id_not_in: List of IDs of the requested CDN resource not equal to the specified values. + Values should be separated by a comma. + + size_eq: Response size in bytes equal to the specified value. + + size_gt: Response size in bytes greater than the specified value. + + size_gte: Response size in bytes greater than or equal to the specified value. + + size_in: List of response sizes in bytes. Values should be separated by a comma. + + size_lt: Response size in bytes less than the specified value. + + size_lte: Response size in bytes less than or equal to the specified value. + + size_ne: Response size in bytes not equal to the specified value. + + size_not_in: List of response sizes in bytes not equal to the specified values. Values should + be separated by + + sort: Sorting rules. + + Possible values: + + - **method** - Request HTTP method. + - **`client_ip`** - IP address of the client who sent the request. + - **status** - Status code in the response. + - **size** - Response size in bytes. + - **cname** - Custom domain of the requested resource. + - **`resource_id`** - ID of the requested CDN resource. + - **`cache_status`** - Caching status. + - **datacenter** - Data center where request was processed. + - **timestamp** - Date and time when the request was made. + + May include multiple values separated by a comma. + + Example: + + - &sort=-timestamp,status + + status_eq: Status code in the response equal to the specified value. + + status_gt: Status code in the response greater than the specified value. + + status_gte: Status code in the response greater than or equal to the specified value. + + status_in: List of status codes in the response. Values should be separated by a comma. + + status_lt: Status code in the response less than the specified value. + + status_lte: Status code in the response less than or equal to the specified value. + + status_ne: Status code in the response not equal to the specified value. + + status_not_in: List of status codes not in the response. Values should be separated by a comma. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "application/zip", **(extra_headers or {})} + return self._get( + "/cdn/advanced/v1/logs/download", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "format": format, + "from_": from_, + "to": to, + "cache_status_eq": cache_status_eq, + "cache_status_in": cache_status_in, + "cache_status_ne": cache_status_ne, + "cache_status_not_in": cache_status_not_in, + "client_ip_eq": client_ip_eq, + "client_ip_in": client_ip_in, + "client_ip_ne": client_ip_ne, + "client_ip_not_in": client_ip_not_in, + "cname_contains": cname_contains, + "cname_eq": cname_eq, + "cname_in": cname_in, + "cname_ne": cname_ne, + "cname_not_in": cname_not_in, + "datacenter_eq": datacenter_eq, + "datacenter_in": datacenter_in, + "datacenter_ne": datacenter_ne, + "datacenter_not_in": datacenter_not_in, + "fields": fields, + "limit": limit, + "method_eq": method_eq, + "method_in": method_in, + "method_ne": method_ne, + "method_not_in": method_not_in, + "offset": offset, + "resource_id_eq": resource_id_eq, + "resource_id_gt": resource_id_gt, + "resource_id_gte": resource_id_gte, + "resource_id_in": resource_id_in, + "resource_id_lt": resource_id_lt, + "resource_id_lte": resource_id_lte, + "resource_id_ne": resource_id_ne, + "resource_id_not_in": resource_id_not_in, + "size_eq": size_eq, + "size_gt": size_gt, + "size_gte": size_gte, + "size_in": size_in, + "size_lt": size_lt, + "size_lte": size_lte, + "size_ne": size_ne, + "size_not_in": size_not_in, + "sort": sort, + "status_eq": status_eq, + "status_gt": status_gt, + "status_gte": status_gte, + "status_in": status_in, + "status_lt": status_lt, + "status_lte": status_lte, + "status_ne": status_ne, + "status_not_in": status_not_in, + }, + log_download_params.LogDownloadParams, + ), + ), + cast_to=BinaryAPIResponse, + ) + + +class AsyncLogsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncLogsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncLogsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncLogsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncLogsResourceWithStreamingResponse(self) + + def list( + self, + *, + from_: str, + to: str, + cache_status_eq: str | Omit = omit, + cache_status_in: str | Omit = omit, + cache_status_ne: str | Omit = omit, + cache_status_not_in: str | Omit = omit, + client_ip_eq: str | Omit = omit, + client_ip_in: str | Omit = omit, + client_ip_ne: str | Omit = omit, + client_ip_not_in: str | Omit = omit, + cname_contains: str | Omit = omit, + cname_eq: str | Omit = omit, + cname_in: str | Omit = omit, + cname_ne: str | Omit = omit, + cname_not_in: str | Omit = omit, + datacenter_eq: str | Omit = omit, + datacenter_in: str | Omit = omit, + datacenter_ne: str | Omit = omit, + datacenter_not_in: str | Omit = omit, + fields: str | Omit = omit, + limit: int | Omit = omit, + method_eq: str | Omit = omit, + method_in: str | Omit = omit, + method_ne: str | Omit = omit, + method_not_in: str | Omit = omit, + offset: int | Omit = omit, + ordering: str | Omit = omit, + resource_id_eq: int | Omit = omit, + resource_id_gt: int | Omit = omit, + resource_id_gte: int | Omit = omit, + resource_id_in: str | Omit = omit, + resource_id_lt: int | Omit = omit, + resource_id_lte: int | Omit = omit, + resource_id_ne: int | Omit = omit, + resource_id_not_in: str | Omit = omit, + size_eq: int | Omit = omit, + size_gt: int | Omit = omit, + size_gte: int | Omit = omit, + size_in: str | Omit = omit, + size_lt: int | Omit = omit, + size_lte: int | Omit = omit, + size_ne: int | Omit = omit, + size_not_in: str | Omit = omit, + status_eq: int | Omit = omit, + status_gt: int | Omit = omit, + status_gte: int | Omit = omit, + status_in: str | Omit = omit, + status_lt: int | Omit = omit, + status_lte: int | Omit = omit, + status_ne: int | Omit = omit, + status_not_in: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Data, AsyncOffsetPageCDNLogs[Data]]: + """ + Get CDN logs for up to 3 days starting today. + + You can filter logs using query parameters by client IP, CDN resource, date, + path and etc. + + To filter the CDN logs by 2xx status codes, use: + + - &`status__gte`=200&`status__lt`=300 + + Args: + from_: Start date and time of the requested time period (ISO 8601/RFC 3339 format, + UTC.) + + Difference between "from" and "to" cannot exceed 6 hours. + + Examples: + + - &from=2021-06-14T00:00:00Z + - &from=2021-06-14T00:00:00.000Z + + to: End date and time of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + Difference between "from" and "to" cannot exceed 6 hours. + + Examples: + + - &to=2021-06-15T00:00:00Z + - &to=2021-06-15T00:00:00.000Z + + cache_status_eq: Caching status. Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', + 'PENDING', 'UPDATING', 'REVALIDATED', 'HIT', '-'. + + cache_status_in: List of caching statuses. Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', + 'PENDING', 'UPDATING', 'REVALIDATED', 'HIT', '-'. Values should be separated by + a comma. + + cache_status_ne: Caching status not equal to the specified value. Possible values: 'MISS', + 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', 'REVALIDATED', 'HIT', '-'. + + cache_status_not_in: + List of caching statuses not equal to the specified values. Possible values: + 'MISS', 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', 'REVALIDATED', + 'HIT', '-'. Values should be separated by a comma. + + client_ip_eq: IP address of the client who sent the request. + + client_ip_in: List of IP addresses of the clients who sent the request. + + client_ip_ne: IP address of the client who did not send the request. + + client_ip_not_in: List of IP addresses of the clients who did not send the request. + + cname_contains: Part of the custom domain of the requested CDN resource. Minimum length is 3 + characters. + + cname_eq: Custom domain of the requested CDN resource. + + cname_in: List of custom domains of the requested CDN resource. Values should be separated + by a comma. + + cname_ne: Custom domain of the requested CDN resource not equal to the specified value. + + cname_not_in: List of custom domains of the requested CDN resource not equal to the specified + values. Values should be separated by a comma. + + datacenter_eq: Data center where request was processed. + + datacenter_in: List of data centers where request was processed. Values should be separated by + a comma. + + datacenter_ne: Data center where request was not processed. + + datacenter_not_in: List of data centers where request was not processed. Values should be separated + by a comma. + + fields: A comma-separated list of returned fields. + + Supported fields are presented in the responses section. + + Example: + + - &fields=timestamp,path,status + + limit: Maximum number of log records in the response. + + method_eq: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. + + method_in: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. Values should be separated by a + comma. + + method_ne: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. + + method_not_in: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. Values should be separated by a + comma. + + offset: Number of log records to skip starting from the beginning of the requested + period. + + ordering: Sorting rules. + + Possible values: + + - **method** - Request HTTP method. + - **`client_ip`** - IP address of the client who sent the request. + - **status** - Status code in the response. + - **size** - Response size in bytes. + - **cname** - Custom domain of the requested resource. + - **`resource_id`** - ID of the requested CDN resource. + - **`cache_status`** - Caching status. + - **datacenter** - Data center where request was processed. + - **timestamp** - Date and time when the request was made. + + Parameter may have multiple values separated by a comma. + + By default, ascending sorting is applied. To sort in descending order, add '-' + prefix. + + Example: + + - &ordering=-timestamp,status + + resource_id_eq: ID of the requested CDN resource equal to the specified value. + + resource_id_gt: ID of the requested CDN resource greater than the specified value. + + resource_id_gte: ID of the requested CDN resource greater than or equal to the specified value. + + resource_id_in: List of IDs of the requested CDN resource. Values should be separated by a + comma. + + resource_id_lt: ID of the requested CDN resource less than the specified value. + + resource_id_lte: ID of the requested CDN resource less than or equal to the specified value. + + resource_id_ne: ID of the requested CDN resource not equal to the specified value. + + resource_id_not_in: List of IDs of the requested CDN resource not equal to the specified values. + Values should be separated by a comma. + + size_eq: Response size in bytes equal to the specified value. + + size_gt: Response size in bytes greater than the specified value. + + size_gte: Response size in bytes greater than or equal to the specified value. + + size_in: List of response sizes in bytes. Values should be separated by a comma. + + size_lt: Response size in bytes less than the specified value. + + size_lte: Response size in bytes less than or equal to the specified value. + + size_ne: Response size in bytes not equal to the specified value. + + size_not_in: List of response sizes in bytes not equal to the specified values. Values should + be separated by + + status_eq: Status code in the response equal to the specified value. + + status_gt: Status code in the response greater than the specified value. + + status_gte: Status code in the response greater than or equal to the specified value. + + status_in: List of status codes in the response. Values should be separated by a comma. + + status_lt: Status code in the response less than the specified value. + + status_lte: Status code in the response less than or equal to the specified value. + + status_ne: Status code in the response not equal to the specified value. + + status_not_in: List of status codes not in the response. Values should be separated by a comma. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cdn/advanced/v1/logs", + page=AsyncOffsetPageCDNLogs[Data], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "to": to, + "cache_status_eq": cache_status_eq, + "cache_status_in": cache_status_in, + "cache_status_ne": cache_status_ne, + "cache_status_not_in": cache_status_not_in, + "client_ip_eq": client_ip_eq, + "client_ip_in": client_ip_in, + "client_ip_ne": client_ip_ne, + "client_ip_not_in": client_ip_not_in, + "cname_contains": cname_contains, + "cname_eq": cname_eq, + "cname_in": cname_in, + "cname_ne": cname_ne, + "cname_not_in": cname_not_in, + "datacenter_eq": datacenter_eq, + "datacenter_in": datacenter_in, + "datacenter_ne": datacenter_ne, + "datacenter_not_in": datacenter_not_in, + "fields": fields, + "limit": limit, + "method_eq": method_eq, + "method_in": method_in, + "method_ne": method_ne, + "method_not_in": method_not_in, + "offset": offset, + "ordering": ordering, + "resource_id_eq": resource_id_eq, + "resource_id_gt": resource_id_gt, + "resource_id_gte": resource_id_gte, + "resource_id_in": resource_id_in, + "resource_id_lt": resource_id_lt, + "resource_id_lte": resource_id_lte, + "resource_id_ne": resource_id_ne, + "resource_id_not_in": resource_id_not_in, + "size_eq": size_eq, + "size_gt": size_gt, + "size_gte": size_gte, + "size_in": size_in, + "size_lt": size_lt, + "size_lte": size_lte, + "size_ne": size_ne, + "size_not_in": size_not_in, + "status_eq": status_eq, + "status_gt": status_gt, + "status_gte": status_gte, + "status_in": status_in, + "status_lt": status_lt, + "status_lte": status_lte, + "status_ne": status_ne, + "status_not_in": status_not_in, + }, + log_list_params.LogListParams, + ), + ), + model=Data, + ) + + async def download( + self, + *, + format: str, + from_: str, + to: str, + cache_status_eq: str | Omit = omit, + cache_status_in: str | Omit = omit, + cache_status_ne: str | Omit = omit, + cache_status_not_in: str | Omit = omit, + client_ip_eq: str | Omit = omit, + client_ip_in: str | Omit = omit, + client_ip_ne: str | Omit = omit, + client_ip_not_in: str | Omit = omit, + cname_contains: str | Omit = omit, + cname_eq: str | Omit = omit, + cname_in: str | Omit = omit, + cname_ne: str | Omit = omit, + cname_not_in: str | Omit = omit, + datacenter_eq: str | Omit = omit, + datacenter_in: str | Omit = omit, + datacenter_ne: str | Omit = omit, + datacenter_not_in: str | Omit = omit, + fields: str | Omit = omit, + limit: int | Omit = omit, + method_eq: str | Omit = omit, + method_in: str | Omit = omit, + method_ne: str | Omit = omit, + method_not_in: str | Omit = omit, + offset: int | Omit = omit, + resource_id_eq: int | Omit = omit, + resource_id_gt: int | Omit = omit, + resource_id_gte: int | Omit = omit, + resource_id_in: str | Omit = omit, + resource_id_lt: int | Omit = omit, + resource_id_lte: int | Omit = omit, + resource_id_ne: int | Omit = omit, + resource_id_not_in: str | Omit = omit, + size_eq: int | Omit = omit, + size_gt: int | Omit = omit, + size_gte: int | Omit = omit, + size_in: str | Omit = omit, + size_lt: int | Omit = omit, + size_lte: int | Omit = omit, + size_ne: int | Omit = omit, + size_not_in: str | Omit = omit, + sort: str | Omit = omit, + status_eq: int | Omit = omit, + status_gt: int | Omit = omit, + status_gte: int | Omit = omit, + status_in: str | Omit = omit, + status_lt: int | Omit = omit, + status_lte: int | Omit = omit, + status_ne: int | Omit = omit, + status_not_in: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncBinaryAPIResponse: + """ + Download CDN logs for up to 3 days starting today. + + You can filter logs using query params by client IP, CDN resource, date, path + and etc. + + Args: + format: Output format. + + Possible values: + + - csv + - tsv + + from_: Start date and time of the requested time period (ISO 8601/RFC 3339 format, + UTC.) + + Difference between "from" and "to" cannot exceed 6 hours. + + Examples: + + - &from=2021-06-14T00:00:00Z + - &from=2021-06-14T00:00:00.000Z + + to: End date and time of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + Difference between "from" and "to" cannot exceed 6 hours. + + Examples: + + - &to=2021-06-15T00:00:00Z + - &to=2021-06-15T00:00:00.000Z + + cache_status_eq: Caching status. Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', + 'PENDING', 'UPDATING', 'REVALIDATED', 'HIT', '-'. + + cache_status_in: List of caching statuses. Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', + 'PENDING', 'UPDATING', 'REVALIDATED', 'HIT', '-'. Values should be separated by + a comma. + + cache_status_ne: Caching status not equal to the specified value. Possible values: 'MISS', + 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', 'REVALIDATED', 'HIT', '-'. + + cache_status_not_in: + List of caching statuses not equal to the specified values. Possible values: + 'MISS', 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', 'REVALIDATED', + 'HIT', '-'. Values should be separated by a comma. + + client_ip_eq: IP address of the client who sent the request. + + client_ip_in: List of IP addresses of the clients who sent the request. + + client_ip_ne: IP address of the client who did not send the request. + + client_ip_not_in: List of IP addresses of the clients who did not send the request. + + cname_contains: Part of the custom domain of the requested CDN resource. Minimum length is 3 + characters. + + cname_eq: Custom domain of the requested CDN resource. + + cname_in: List of custom domains of the requested CDN resource. Values should be separated + by a comma. + + cname_ne: Custom domain of the requested CDN resource not equal to the specified value. + + cname_not_in: List of custom domains of the requested CDN resource not equal to the specified + values. Values should be separated by a comma. + + datacenter_eq: Data center where request was processed. + + datacenter_in: List of data centers where request was processed. Values should be separated by + a comma. + + datacenter_ne: Data center where request was not processed. + + datacenter_not_in: List of data centers where request was not processed. Values should be separated + by a comma. + + fields: A comma-separated list of returned fields. + + Supported fields are presented in the responses section. + + Example: + + - &fields=timestamp,path,status + + limit: Maximum number of log records in the response. + + method_eq: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. + + method_in: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. Values should be separated by a + comma. + + method_ne: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. + + method_not_in: Request HTTP method. Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', + 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'. Values should be separated by a + comma. + + offset: Number of log records to skip starting from the beginning of the requested + period. + + resource_id_eq: ID of the requested CDN resource equal to the specified value. + + resource_id_gt: ID of the requested CDN resource greater than the specified value. + + resource_id_gte: ID of the requested CDN resource greater than or equal to the specified value. + + resource_id_in: List of IDs of the requested CDN resource. Values should be separated by a + comma. + + resource_id_lt: ID of the requested CDN resource less than the specified value. + + resource_id_lte: ID of the requested CDN resource less than or equal to the specified value. + + resource_id_ne: ID of the requested CDN resource not equal to the specified value. + + resource_id_not_in: List of IDs of the requested CDN resource not equal to the specified values. + Values should be separated by a comma. + + size_eq: Response size in bytes equal to the specified value. + + size_gt: Response size in bytes greater than the specified value. + + size_gte: Response size in bytes greater than or equal to the specified value. + + size_in: List of response sizes in bytes. Values should be separated by a comma. + + size_lt: Response size in bytes less than the specified value. + + size_lte: Response size in bytes less than or equal to the specified value. + + size_ne: Response size in bytes not equal to the specified value. + + size_not_in: List of response sizes in bytes not equal to the specified values. Values should + be separated by + + sort: Sorting rules. + + Possible values: + + - **method** - Request HTTP method. + - **`client_ip`** - IP address of the client who sent the request. + - **status** - Status code in the response. + - **size** - Response size in bytes. + - **cname** - Custom domain of the requested resource. + - **`resource_id`** - ID of the requested CDN resource. + - **`cache_status`** - Caching status. + - **datacenter** - Data center where request was processed. + - **timestamp** - Date and time when the request was made. + + May include multiple values separated by a comma. + + Example: + + - &sort=-timestamp,status + + status_eq: Status code in the response equal to the specified value. + + status_gt: Status code in the response greater than the specified value. + + status_gte: Status code in the response greater than or equal to the specified value. + + status_in: List of status codes in the response. Values should be separated by a comma. + + status_lt: Status code in the response less than the specified value. + + status_lte: Status code in the response less than or equal to the specified value. + + status_ne: Status code in the response not equal to the specified value. + + status_not_in: List of status codes not in the response. Values should be separated by a comma. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "application/zip", **(extra_headers or {})} + return await self._get( + "/cdn/advanced/v1/logs/download", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "format": format, + "from_": from_, + "to": to, + "cache_status_eq": cache_status_eq, + "cache_status_in": cache_status_in, + "cache_status_ne": cache_status_ne, + "cache_status_not_in": cache_status_not_in, + "client_ip_eq": client_ip_eq, + "client_ip_in": client_ip_in, + "client_ip_ne": client_ip_ne, + "client_ip_not_in": client_ip_not_in, + "cname_contains": cname_contains, + "cname_eq": cname_eq, + "cname_in": cname_in, + "cname_ne": cname_ne, + "cname_not_in": cname_not_in, + "datacenter_eq": datacenter_eq, + "datacenter_in": datacenter_in, + "datacenter_ne": datacenter_ne, + "datacenter_not_in": datacenter_not_in, + "fields": fields, + "limit": limit, + "method_eq": method_eq, + "method_in": method_in, + "method_ne": method_ne, + "method_not_in": method_not_in, + "offset": offset, + "resource_id_eq": resource_id_eq, + "resource_id_gt": resource_id_gt, + "resource_id_gte": resource_id_gte, + "resource_id_in": resource_id_in, + "resource_id_lt": resource_id_lt, + "resource_id_lte": resource_id_lte, + "resource_id_ne": resource_id_ne, + "resource_id_not_in": resource_id_not_in, + "size_eq": size_eq, + "size_gt": size_gt, + "size_gte": size_gte, + "size_in": size_in, + "size_lt": size_lt, + "size_lte": size_lte, + "size_ne": size_ne, + "size_not_in": size_not_in, + "sort": sort, + "status_eq": status_eq, + "status_gt": status_gt, + "status_gte": status_gte, + "status_in": status_in, + "status_lt": status_lt, + "status_lte": status_lte, + "status_ne": status_ne, + "status_not_in": status_not_in, + }, + log_download_params.LogDownloadParams, + ), + ), + cast_to=AsyncBinaryAPIResponse, + ) + + +class LogsResourceWithRawResponse: + def __init__(self, logs: LogsResource) -> None: + self._logs = logs + + self.list = to_raw_response_wrapper( + logs.list, + ) + self.download = to_custom_raw_response_wrapper( + logs.download, + BinaryAPIResponse, + ) + + +class AsyncLogsResourceWithRawResponse: + def __init__(self, logs: AsyncLogsResource) -> None: + self._logs = logs + + self.list = async_to_raw_response_wrapper( + logs.list, + ) + self.download = async_to_custom_raw_response_wrapper( + logs.download, + AsyncBinaryAPIResponse, + ) + + +class LogsResourceWithStreamingResponse: + def __init__(self, logs: LogsResource) -> None: + self._logs = logs + + self.list = to_streamed_response_wrapper( + logs.list, + ) + self.download = to_custom_streamed_response_wrapper( + logs.download, + StreamedBinaryAPIResponse, + ) + + +class AsyncLogsResourceWithStreamingResponse: + def __init__(self, logs: AsyncLogsResource) -> None: + self._logs = logs + + self.list = async_to_streamed_response_wrapper( + logs.list, + ) + self.download = async_to_custom_streamed_response_wrapper( + logs.download, + AsyncStreamedBinaryAPIResponse, + ) diff --git a/src/gcore/resources/cdn/logs_uploader/__init__.py b/src/gcore/resources/cdn/logs_uploader/__init__.py new file mode 100644 index 00000000..d5c0911f --- /dev/null +++ b/src/gcore/resources/cdn/logs_uploader/__init__.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .configs import ( + ConfigsResource, + AsyncConfigsResource, + ConfigsResourceWithRawResponse, + AsyncConfigsResourceWithRawResponse, + ConfigsResourceWithStreamingResponse, + AsyncConfigsResourceWithStreamingResponse, +) +from .targets import ( + TargetsResource, + AsyncTargetsResource, + TargetsResourceWithRawResponse, + AsyncTargetsResourceWithRawResponse, + TargetsResourceWithStreamingResponse, + AsyncTargetsResourceWithStreamingResponse, +) +from .policies import ( + PoliciesResource, + AsyncPoliciesResource, + PoliciesResourceWithRawResponse, + AsyncPoliciesResourceWithRawResponse, + PoliciesResourceWithStreamingResponse, + AsyncPoliciesResourceWithStreamingResponse, +) +from .logs_uploader import ( + LogsUploaderResource, + AsyncLogsUploaderResource, + LogsUploaderResourceWithRawResponse, + AsyncLogsUploaderResourceWithRawResponse, + LogsUploaderResourceWithStreamingResponse, + AsyncLogsUploaderResourceWithStreamingResponse, +) + +__all__ = [ + "PoliciesResource", + "AsyncPoliciesResource", + "PoliciesResourceWithRawResponse", + "AsyncPoliciesResourceWithRawResponse", + "PoliciesResourceWithStreamingResponse", + "AsyncPoliciesResourceWithStreamingResponse", + "TargetsResource", + "AsyncTargetsResource", + "TargetsResourceWithRawResponse", + "AsyncTargetsResourceWithRawResponse", + "TargetsResourceWithStreamingResponse", + "AsyncTargetsResourceWithStreamingResponse", + "ConfigsResource", + "AsyncConfigsResource", + "ConfigsResourceWithRawResponse", + "AsyncConfigsResourceWithRawResponse", + "ConfigsResourceWithStreamingResponse", + "AsyncConfigsResourceWithStreamingResponse", + "LogsUploaderResource", + "AsyncLogsUploaderResource", + "LogsUploaderResourceWithRawResponse", + "AsyncLogsUploaderResourceWithRawResponse", + "LogsUploaderResourceWithStreamingResponse", + "AsyncLogsUploaderResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cdn/logs_uploader/configs.py b/src/gcore/resources/cdn/logs_uploader/configs.py new file mode 100644 index 00000000..66fb217f --- /dev/null +++ b/src/gcore/resources/cdn/logs_uploader/configs.py @@ -0,0 +1,840 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cdn.logs_uploader import ( + config_list_params, + config_create_params, + config_update_params, + config_replace_params, +) +from ....types.cdn.logs_uploader_validation import LogsUploaderValidation +from ....types.cdn.logs_uploader.logs_uploader_config import LogsUploaderConfig +from ....types.cdn.logs_uploader.logs_uploader_config_list import LogsUploaderConfigList + +__all__ = ["ConfigsResource", "AsyncConfigsResource"] + + +class ConfigsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ConfigsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ConfigsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ConfigsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ConfigsResourceWithStreamingResponse(self) + + def create( + self, + *, + name: str, + policy: int, + target: int, + enabled: bool | Omit = omit, + for_all_resources: bool | Omit = omit, + resources: Iterable[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderConfig: + """ + Create logs uploader config. + + Args: + name: Name of the config. + + policy: ID of the policy that should be assigned to given config. + + target: ID of the target to which logs should be uploaded. + + enabled: Enables or disables the config. + + for_all_resources: If set to true, the config will be applied to all CDN resources. If set to + false, the config will be applied to the resources specified in the `resources` + field. + + resources: List of resource IDs to which the config should be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/cdn/logs_uploader/configs", + body=maybe_transform( + { + "name": name, + "policy": policy, + "target": target, + "enabled": enabled, + "for_all_resources": for_all_resources, + "resources": resources, + }, + config_create_params.ConfigCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderConfig, + ) + + def update( + self, + id: int, + *, + enabled: bool | Omit = omit, + for_all_resources: bool | Omit = omit, + name: str | Omit = omit, + policy: int | Omit = omit, + resources: Iterable[int] | Omit = omit, + target: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderConfig: + """ + Change logs uploader config partially. + + Args: + enabled: Enables or disables the config. + + for_all_resources: If set to true, the config will be applied to all CDN resources. If set to + false, the config will be applied to the resources specified in the `resources` + field. + + name: Name of the config. + + policy: ID of the policy that should be assigned to given config. + + resources: List of resource IDs to which the config should be applied. + + target: ID of the target to which logs should be uploaded. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/cdn/logs_uploader/configs/{id}", + body=maybe_transform( + { + "enabled": enabled, + "for_all_resources": for_all_resources, + "name": name, + "policy": policy, + "resources": resources, + "target": target, + }, + config_update_params.ConfigUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderConfig, + ) + + def list( + self, + *, + resource_ids: Iterable[int] | Omit = omit, + search: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderConfigList: + """ + Get list of logs uploader configs. + + Args: + resource_ids: Filter by ids of CDN resources that are assigned to given config. + + search: Search by config name or id. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/logs_uploader/configs", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "resource_ids": resource_ids, + "search": search, + }, + config_list_params.ConfigListParams, + ), + ), + cast_to=LogsUploaderConfigList, + ) + + def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete the logs uploader config from the system permanently. + + Notes: + + - **Irreversibility**: This action is irreversible. Once deleted, the logs + uploader config cannot be recovered. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cdn/logs_uploader/configs/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderConfig: + """ + Get information about logs uploader config. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cdn/logs_uploader/configs/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderConfig, + ) + + def replace( + self, + id: int, + *, + name: str, + policy: int, + target: int, + enabled: bool | Omit = omit, + for_all_resources: bool | Omit = omit, + resources: Iterable[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderConfig: + """ + Change logs uploader config. + + Args: + name: Name of the config. + + policy: ID of the policy that should be assigned to given config. + + target: ID of the target to which logs should be uploaded. + + enabled: Enables or disables the config. + + for_all_resources: If set to true, the config will be applied to all CDN resources. If set to + false, the config will be applied to the resources specified in the `resources` + field. + + resources: List of resource IDs to which the config should be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/cdn/logs_uploader/configs/{id}", + body=maybe_transform( + { + "name": name, + "policy": policy, + "target": target, + "enabled": enabled, + "for_all_resources": for_all_resources, + "resources": resources, + }, + config_replace_params.ConfigReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderConfig, + ) + + def validate( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderValidation: + """ + Validate logs uploader config. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/cdn/logs_uploader/configs/{id}/validate", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderValidation, + ) + + +class AsyncConfigsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncConfigsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncConfigsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncConfigsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncConfigsResourceWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + policy: int, + target: int, + enabled: bool | Omit = omit, + for_all_resources: bool | Omit = omit, + resources: Iterable[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderConfig: + """ + Create logs uploader config. + + Args: + name: Name of the config. + + policy: ID of the policy that should be assigned to given config. + + target: ID of the target to which logs should be uploaded. + + enabled: Enables or disables the config. + + for_all_resources: If set to true, the config will be applied to all CDN resources. If set to + false, the config will be applied to the resources specified in the `resources` + field. + + resources: List of resource IDs to which the config should be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/cdn/logs_uploader/configs", + body=await async_maybe_transform( + { + "name": name, + "policy": policy, + "target": target, + "enabled": enabled, + "for_all_resources": for_all_resources, + "resources": resources, + }, + config_create_params.ConfigCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderConfig, + ) + + async def update( + self, + id: int, + *, + enabled: bool | Omit = omit, + for_all_resources: bool | Omit = omit, + name: str | Omit = omit, + policy: int | Omit = omit, + resources: Iterable[int] | Omit = omit, + target: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderConfig: + """ + Change logs uploader config partially. + + Args: + enabled: Enables or disables the config. + + for_all_resources: If set to true, the config will be applied to all CDN resources. If set to + false, the config will be applied to the resources specified in the `resources` + field. + + name: Name of the config. + + policy: ID of the policy that should be assigned to given config. + + resources: List of resource IDs to which the config should be applied. + + target: ID of the target to which logs should be uploaded. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/cdn/logs_uploader/configs/{id}", + body=await async_maybe_transform( + { + "enabled": enabled, + "for_all_resources": for_all_resources, + "name": name, + "policy": policy, + "resources": resources, + "target": target, + }, + config_update_params.ConfigUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderConfig, + ) + + async def list( + self, + *, + resource_ids: Iterable[int] | Omit = omit, + search: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderConfigList: + """ + Get list of logs uploader configs. + + Args: + resource_ids: Filter by ids of CDN resources that are assigned to given config. + + search: Search by config name or id. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/logs_uploader/configs", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "resource_ids": resource_ids, + "search": search, + }, + config_list_params.ConfigListParams, + ), + ), + cast_to=LogsUploaderConfigList, + ) + + async def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete the logs uploader config from the system permanently. + + Notes: + + - **Irreversibility**: This action is irreversible. Once deleted, the logs + uploader config cannot be recovered. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cdn/logs_uploader/configs/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderConfig: + """ + Get information about logs uploader config. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cdn/logs_uploader/configs/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderConfig, + ) + + async def replace( + self, + id: int, + *, + name: str, + policy: int, + target: int, + enabled: bool | Omit = omit, + for_all_resources: bool | Omit = omit, + resources: Iterable[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderConfig: + """ + Change logs uploader config. + + Args: + name: Name of the config. + + policy: ID of the policy that should be assigned to given config. + + target: ID of the target to which logs should be uploaded. + + enabled: Enables or disables the config. + + for_all_resources: If set to true, the config will be applied to all CDN resources. If set to + false, the config will be applied to the resources specified in the `resources` + field. + + resources: List of resource IDs to which the config should be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/cdn/logs_uploader/configs/{id}", + body=await async_maybe_transform( + { + "name": name, + "policy": policy, + "target": target, + "enabled": enabled, + "for_all_resources": for_all_resources, + "resources": resources, + }, + config_replace_params.ConfigReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderConfig, + ) + + async def validate( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderValidation: + """ + Validate logs uploader config. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/cdn/logs_uploader/configs/{id}/validate", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderValidation, + ) + + +class ConfigsResourceWithRawResponse: + def __init__(self, configs: ConfigsResource) -> None: + self._configs = configs + + self.create = to_raw_response_wrapper( + configs.create, + ) + self.update = to_raw_response_wrapper( + configs.update, + ) + self.list = to_raw_response_wrapper( + configs.list, + ) + self.delete = to_raw_response_wrapper( + configs.delete, + ) + self.get = to_raw_response_wrapper( + configs.get, + ) + self.replace = to_raw_response_wrapper( + configs.replace, + ) + self.validate = to_raw_response_wrapper( + configs.validate, + ) + + +class AsyncConfigsResourceWithRawResponse: + def __init__(self, configs: AsyncConfigsResource) -> None: + self._configs = configs + + self.create = async_to_raw_response_wrapper( + configs.create, + ) + self.update = async_to_raw_response_wrapper( + configs.update, + ) + self.list = async_to_raw_response_wrapper( + configs.list, + ) + self.delete = async_to_raw_response_wrapper( + configs.delete, + ) + self.get = async_to_raw_response_wrapper( + configs.get, + ) + self.replace = async_to_raw_response_wrapper( + configs.replace, + ) + self.validate = async_to_raw_response_wrapper( + configs.validate, + ) + + +class ConfigsResourceWithStreamingResponse: + def __init__(self, configs: ConfigsResource) -> None: + self._configs = configs + + self.create = to_streamed_response_wrapper( + configs.create, + ) + self.update = to_streamed_response_wrapper( + configs.update, + ) + self.list = to_streamed_response_wrapper( + configs.list, + ) + self.delete = to_streamed_response_wrapper( + configs.delete, + ) + self.get = to_streamed_response_wrapper( + configs.get, + ) + self.replace = to_streamed_response_wrapper( + configs.replace, + ) + self.validate = to_streamed_response_wrapper( + configs.validate, + ) + + +class AsyncConfigsResourceWithStreamingResponse: + def __init__(self, configs: AsyncConfigsResource) -> None: + self._configs = configs + + self.create = async_to_streamed_response_wrapper( + configs.create, + ) + self.update = async_to_streamed_response_wrapper( + configs.update, + ) + self.list = async_to_streamed_response_wrapper( + configs.list, + ) + self.delete = async_to_streamed_response_wrapper( + configs.delete, + ) + self.get = async_to_streamed_response_wrapper( + configs.get, + ) + self.replace = async_to_streamed_response_wrapper( + configs.replace, + ) + self.validate = async_to_streamed_response_wrapper( + configs.validate, + ) diff --git a/src/gcore/resources/cdn/logs_uploader/logs_uploader.py b/src/gcore/resources/cdn/logs_uploader/logs_uploader.py new file mode 100644 index 00000000..9d7c3aeb --- /dev/null +++ b/src/gcore/resources/cdn/logs_uploader/logs_uploader.py @@ -0,0 +1,166 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .configs import ( + ConfigsResource, + AsyncConfigsResource, + ConfigsResourceWithRawResponse, + AsyncConfigsResourceWithRawResponse, + ConfigsResourceWithStreamingResponse, + AsyncConfigsResourceWithStreamingResponse, +) +from .targets import ( + TargetsResource, + AsyncTargetsResource, + TargetsResourceWithRawResponse, + AsyncTargetsResourceWithRawResponse, + TargetsResourceWithStreamingResponse, + AsyncTargetsResourceWithStreamingResponse, +) +from .policies import ( + PoliciesResource, + AsyncPoliciesResource, + PoliciesResourceWithRawResponse, + AsyncPoliciesResourceWithRawResponse, + PoliciesResourceWithStreamingResponse, + AsyncPoliciesResourceWithStreamingResponse, +) +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource + +__all__ = ["LogsUploaderResource", "AsyncLogsUploaderResource"] + + +class LogsUploaderResource(SyncAPIResource): + @cached_property + def policies(self) -> PoliciesResource: + return PoliciesResource(self._client) + + @cached_property + def targets(self) -> TargetsResource: + return TargetsResource(self._client) + + @cached_property + def configs(self) -> ConfigsResource: + return ConfigsResource(self._client) + + @cached_property + def with_raw_response(self) -> LogsUploaderResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return LogsUploaderResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> LogsUploaderResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return LogsUploaderResourceWithStreamingResponse(self) + + +class AsyncLogsUploaderResource(AsyncAPIResource): + @cached_property + def policies(self) -> AsyncPoliciesResource: + return AsyncPoliciesResource(self._client) + + @cached_property + def targets(self) -> AsyncTargetsResource: + return AsyncTargetsResource(self._client) + + @cached_property + def configs(self) -> AsyncConfigsResource: + return AsyncConfigsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncLogsUploaderResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncLogsUploaderResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncLogsUploaderResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncLogsUploaderResourceWithStreamingResponse(self) + + +class LogsUploaderResourceWithRawResponse: + def __init__(self, logs_uploader: LogsUploaderResource) -> None: + self._logs_uploader = logs_uploader + + @cached_property + def policies(self) -> PoliciesResourceWithRawResponse: + return PoliciesResourceWithRawResponse(self._logs_uploader.policies) + + @cached_property + def targets(self) -> TargetsResourceWithRawResponse: + return TargetsResourceWithRawResponse(self._logs_uploader.targets) + + @cached_property + def configs(self) -> ConfigsResourceWithRawResponse: + return ConfigsResourceWithRawResponse(self._logs_uploader.configs) + + +class AsyncLogsUploaderResourceWithRawResponse: + def __init__(self, logs_uploader: AsyncLogsUploaderResource) -> None: + self._logs_uploader = logs_uploader + + @cached_property + def policies(self) -> AsyncPoliciesResourceWithRawResponse: + return AsyncPoliciesResourceWithRawResponse(self._logs_uploader.policies) + + @cached_property + def targets(self) -> AsyncTargetsResourceWithRawResponse: + return AsyncTargetsResourceWithRawResponse(self._logs_uploader.targets) + + @cached_property + def configs(self) -> AsyncConfigsResourceWithRawResponse: + return AsyncConfigsResourceWithRawResponse(self._logs_uploader.configs) + + +class LogsUploaderResourceWithStreamingResponse: + def __init__(self, logs_uploader: LogsUploaderResource) -> None: + self._logs_uploader = logs_uploader + + @cached_property + def policies(self) -> PoliciesResourceWithStreamingResponse: + return PoliciesResourceWithStreamingResponse(self._logs_uploader.policies) + + @cached_property + def targets(self) -> TargetsResourceWithStreamingResponse: + return TargetsResourceWithStreamingResponse(self._logs_uploader.targets) + + @cached_property + def configs(self) -> ConfigsResourceWithStreamingResponse: + return ConfigsResourceWithStreamingResponse(self._logs_uploader.configs) + + +class AsyncLogsUploaderResourceWithStreamingResponse: + def __init__(self, logs_uploader: AsyncLogsUploaderResource) -> None: + self._logs_uploader = logs_uploader + + @cached_property + def policies(self) -> AsyncPoliciesResourceWithStreamingResponse: + return AsyncPoliciesResourceWithStreamingResponse(self._logs_uploader.policies) + + @cached_property + def targets(self) -> AsyncTargetsResourceWithStreamingResponse: + return AsyncTargetsResourceWithStreamingResponse(self._logs_uploader.targets) + + @cached_property + def configs(self) -> AsyncConfigsResourceWithStreamingResponse: + return AsyncConfigsResourceWithStreamingResponse(self._logs_uploader.configs) diff --git a/src/gcore/resources/cdn/logs_uploader/policies.py b/src/gcore/resources/cdn/logs_uploader/policies.py new file mode 100644 index 00000000..e4d15912 --- /dev/null +++ b/src/gcore/resources/cdn/logs_uploader/policies.py @@ -0,0 +1,1207 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable, Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cdn.logs_uploader import ( + policy_list_params, + policy_create_params, + policy_update_params, + policy_replace_params, +) +from ....types.cdn.logs_uploader.logs_uploader_policy import LogsUploaderPolicy +from ....types.cdn.logs_uploader.logs_uploader_policy_list import LogsUploaderPolicyList +from ....types.cdn.logs_uploader.policy_list_fields_response import PolicyListFieldsResponse + +__all__ = ["PoliciesResource", "AsyncPoliciesResource"] + + +class PoliciesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> PoliciesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return PoliciesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PoliciesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return PoliciesResourceWithStreamingResponse(self) + + def create( + self, + *, + date_format: str | Omit = omit, + description: str | Omit = omit, + escape_special_characters: bool | Omit = omit, + field_delimiter: str | Omit = omit, + field_separator: str | Omit = omit, + fields: SequenceNotStr[str] | Omit = omit, + file_name_template: str | Omit = omit, + format_type: Literal["json", ""] | Omit = omit, + include_empty_logs: bool | Omit = omit, + include_shield_logs: bool | Omit = omit, + log_sample_rate: float | Omit = omit, + name: str | Omit = omit, + retry_interval_minutes: int | Omit = omit, + rotate_interval_minutes: int | Omit = omit, + rotate_threshold_lines: int | Omit = omit, + rotate_threshold_mb: Optional[int] | Omit = omit, + tags: Dict[str, str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderPolicy: + """ + Create logs uploader policy. + + Args: + date_format: Date format for logs. + + description: Description of the policy. + + escape_special_characters: When set to true, the service sanitizes string values by escaping characters + that may be unsafe for transport, logging, or downstream processing. + + The following categories of characters are escaped: + + - Control and non-printable characters + - Quotation marks and escape characters + - Characters outside the standard ASCII range + + The resulting output contains only printable ASCII characters. + + field_delimiter: Field delimiter for logs. + + field_separator: Field separator for logs. + + fields: List of fields to include in logs. + + file_name_template: Template for log file name. + + format_type: Format type for logs. + + Possible values: + + - **""** - empty, it means it will apply the format configurations from the + policy. + - **"json"** - output the logs as json lines. + + include_empty_logs: Include empty logs in the upload. + + include_shield_logs: Include logs from origin shielding in the upload. + + log_sample_rate: Sampling rate for logs. A value between 0 and 1 that determines the fraction of + log entries to collect. + + - **1** - collect all logs (default). + - **0.5** - collect approximately 50% of logs. + - **0** - collect no logs (effectively disables logging without removing the + policy). + + name: Name of the policy. + + retry_interval_minutes: Interval in minutes to retry failed uploads. + + rotate_interval_minutes: Interval in minutes to rotate logs. + + rotate_threshold_lines: Threshold in lines to rotate logs. + + rotate_threshold_mb: Threshold in MB to rotate logs. + + tags: Tags allow for dynamic decoration of logs by adding predefined fields to the log + format. These tags serve as customizable key-value pairs that can be included in + log entries to enhance context and readability. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/cdn/logs_uploader/policies", + body=maybe_transform( + { + "date_format": date_format, + "description": description, + "escape_special_characters": escape_special_characters, + "field_delimiter": field_delimiter, + "field_separator": field_separator, + "fields": fields, + "file_name_template": file_name_template, + "format_type": format_type, + "include_empty_logs": include_empty_logs, + "include_shield_logs": include_shield_logs, + "log_sample_rate": log_sample_rate, + "name": name, + "retry_interval_minutes": retry_interval_minutes, + "rotate_interval_minutes": rotate_interval_minutes, + "rotate_threshold_lines": rotate_threshold_lines, + "rotate_threshold_mb": rotate_threshold_mb, + "tags": tags, + }, + policy_create_params.PolicyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderPolicy, + ) + + def update( + self, + id: int, + *, + date_format: str | Omit = omit, + description: str | Omit = omit, + escape_special_characters: bool | Omit = omit, + field_delimiter: str | Omit = omit, + field_separator: str | Omit = omit, + fields: SequenceNotStr[str] | Omit = omit, + file_name_template: str | Omit = omit, + format_type: Literal["json", ""] | Omit = omit, + include_empty_logs: bool | Omit = omit, + include_shield_logs: bool | Omit = omit, + log_sample_rate: float | Omit = omit, + name: str | Omit = omit, + retry_interval_minutes: int | Omit = omit, + rotate_interval_minutes: int | Omit = omit, + rotate_threshold_lines: int | Omit = omit, + rotate_threshold_mb: Optional[int] | Omit = omit, + tags: Dict[str, str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderPolicy: + """ + Change logs uploader policy partially. + + Args: + date_format: Date format for logs. + + description: Description of the policy. + + escape_special_characters: When set to true, the service sanitizes string values by escaping characters + that may be unsafe for transport, logging, or downstream processing. + + The following categories of characters are escaped: + + - Control and non-printable characters + - Quotation marks and escape characters + - Characters outside the standard ASCII range + + The resulting output contains only printable ASCII characters. + + field_delimiter: Field delimiter for logs. + + field_separator: Field separator for logs. + + fields: List of fields to include in logs. + + file_name_template: Template for log file name. + + format_type: Format type for logs. + + Possible values: + + - **""** - empty, it means it will apply the format configurations from the + policy. + - **"json"** - output the logs as json lines. + + include_empty_logs: Include empty logs in the upload. + + include_shield_logs: Include logs from origin shielding in the upload. + + log_sample_rate: Sampling rate for logs. A value between 0 and 1 that determines the fraction of + log entries to collect. + + - **1** - collect all logs (default). + - **0.5** - collect approximately 50% of logs. + - **0** - collect no logs (effectively disables logging without removing the + policy). + + name: Name of the policy. + + retry_interval_minutes: Interval in minutes to retry failed uploads. + + rotate_interval_minutes: Interval in minutes to rotate logs. + + rotate_threshold_lines: Threshold in lines to rotate logs. + + rotate_threshold_mb: Threshold in MB to rotate logs. + + tags: Tags allow for dynamic decoration of logs by adding predefined fields to the log + format. These tags serve as customizable key-value pairs that can be included in + log entries to enhance context and readability. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/cdn/logs_uploader/policies/{id}", + body=maybe_transform( + { + "date_format": date_format, + "description": description, + "escape_special_characters": escape_special_characters, + "field_delimiter": field_delimiter, + "field_separator": field_separator, + "fields": fields, + "file_name_template": file_name_template, + "format_type": format_type, + "include_empty_logs": include_empty_logs, + "include_shield_logs": include_shield_logs, + "log_sample_rate": log_sample_rate, + "name": name, + "retry_interval_minutes": retry_interval_minutes, + "rotate_interval_minutes": rotate_interval_minutes, + "rotate_threshold_lines": rotate_threshold_lines, + "rotate_threshold_mb": rotate_threshold_mb, + "tags": tags, + }, + policy_update_params.PolicyUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderPolicy, + ) + + def list( + self, + *, + config_ids: Iterable[int] | Omit = omit, + search: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderPolicyList: + """ + Get list of logs uploader policies. + + Args: + config_ids: Filter by ids of related logs uploader configs that use given policy. + + search: Search by policy name or id. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/logs_uploader/policies", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "config_ids": config_ids, + "search": search, + }, + policy_list_params.PolicyListParams, + ), + ), + cast_to=LogsUploaderPolicyList, + ) + + def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete the logs uploader policy from the system permanently. + + Notes: + + - **Irreversibility**: This action is irreversible. Once deleted, the logs + uploader policy cannot be recovered. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cdn/logs_uploader/policies/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderPolicy: + """ + Get information about logs uploader policy. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cdn/logs_uploader/policies/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderPolicy, + ) + + def list_fields( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PolicyListFieldsResponse: + """Get list of available fields for logs uploader policy.""" + return self._get( + "/cdn/logs_uploader/policies/fields", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyListFieldsResponse, + ) + + def replace( + self, + id: int, + *, + date_format: str | Omit = omit, + description: str | Omit = omit, + escape_special_characters: bool | Omit = omit, + field_delimiter: str | Omit = omit, + field_separator: str | Omit = omit, + fields: SequenceNotStr[str] | Omit = omit, + file_name_template: str | Omit = omit, + format_type: Literal["json", ""] | Omit = omit, + include_empty_logs: bool | Omit = omit, + include_shield_logs: bool | Omit = omit, + log_sample_rate: float | Omit = omit, + name: str | Omit = omit, + retry_interval_minutes: int | Omit = omit, + rotate_interval_minutes: int | Omit = omit, + rotate_threshold_lines: int | Omit = omit, + rotate_threshold_mb: Optional[int] | Omit = omit, + tags: Dict[str, str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderPolicy: + """ + Change logs uploader policy. + + Args: + date_format: Date format for logs. + + description: Description of the policy. + + escape_special_characters: When set to true, the service sanitizes string values by escaping characters + that may be unsafe for transport, logging, or downstream processing. + + The following categories of characters are escaped: + + - Control and non-printable characters + - Quotation marks and escape characters + - Characters outside the standard ASCII range + + The resulting output contains only printable ASCII characters. + + field_delimiter: Field delimiter for logs. + + field_separator: Field separator for logs. + + fields: List of fields to include in logs. + + file_name_template: Template for log file name. + + format_type: Format type for logs. + + Possible values: + + - **""** - empty, it means it will apply the format configurations from the + policy. + - **"json"** - output the logs as json lines. + + include_empty_logs: Include empty logs in the upload. + + include_shield_logs: Include logs from origin shielding in the upload. + + log_sample_rate: Sampling rate for logs. A value between 0 and 1 that determines the fraction of + log entries to collect. + + - **1** - collect all logs (default). + - **0.5** - collect approximately 50% of logs. + - **0** - collect no logs (effectively disables logging without removing the + policy). + + name: Name of the policy. + + retry_interval_minutes: Interval in minutes to retry failed uploads. + + rotate_interval_minutes: Interval in minutes to rotate logs. + + rotate_threshold_lines: Threshold in lines to rotate logs. + + rotate_threshold_mb: Threshold in MB to rotate logs. + + tags: Tags allow for dynamic decoration of logs by adding predefined fields to the log + format. These tags serve as customizable key-value pairs that can be included in + log entries to enhance context and readability. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/cdn/logs_uploader/policies/{id}", + body=maybe_transform( + { + "date_format": date_format, + "description": description, + "escape_special_characters": escape_special_characters, + "field_delimiter": field_delimiter, + "field_separator": field_separator, + "fields": fields, + "file_name_template": file_name_template, + "format_type": format_type, + "include_empty_logs": include_empty_logs, + "include_shield_logs": include_shield_logs, + "log_sample_rate": log_sample_rate, + "name": name, + "retry_interval_minutes": retry_interval_minutes, + "rotate_interval_minutes": rotate_interval_minutes, + "rotate_threshold_lines": rotate_threshold_lines, + "rotate_threshold_mb": rotate_threshold_mb, + "tags": tags, + }, + policy_replace_params.PolicyReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderPolicy, + ) + + +class AsyncPoliciesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncPoliciesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncPoliciesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPoliciesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncPoliciesResourceWithStreamingResponse(self) + + async def create( + self, + *, + date_format: str | Omit = omit, + description: str | Omit = omit, + escape_special_characters: bool | Omit = omit, + field_delimiter: str | Omit = omit, + field_separator: str | Omit = omit, + fields: SequenceNotStr[str] | Omit = omit, + file_name_template: str | Omit = omit, + format_type: Literal["json", ""] | Omit = omit, + include_empty_logs: bool | Omit = omit, + include_shield_logs: bool | Omit = omit, + log_sample_rate: float | Omit = omit, + name: str | Omit = omit, + retry_interval_minutes: int | Omit = omit, + rotate_interval_minutes: int | Omit = omit, + rotate_threshold_lines: int | Omit = omit, + rotate_threshold_mb: Optional[int] | Omit = omit, + tags: Dict[str, str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderPolicy: + """ + Create logs uploader policy. + + Args: + date_format: Date format for logs. + + description: Description of the policy. + + escape_special_characters: When set to true, the service sanitizes string values by escaping characters + that may be unsafe for transport, logging, or downstream processing. + + The following categories of characters are escaped: + + - Control and non-printable characters + - Quotation marks and escape characters + - Characters outside the standard ASCII range + + The resulting output contains only printable ASCII characters. + + field_delimiter: Field delimiter for logs. + + field_separator: Field separator for logs. + + fields: List of fields to include in logs. + + file_name_template: Template for log file name. + + format_type: Format type for logs. + + Possible values: + + - **""** - empty, it means it will apply the format configurations from the + policy. + - **"json"** - output the logs as json lines. + + include_empty_logs: Include empty logs in the upload. + + include_shield_logs: Include logs from origin shielding in the upload. + + log_sample_rate: Sampling rate for logs. A value between 0 and 1 that determines the fraction of + log entries to collect. + + - **1** - collect all logs (default). + - **0.5** - collect approximately 50% of logs. + - **0** - collect no logs (effectively disables logging without removing the + policy). + + name: Name of the policy. + + retry_interval_minutes: Interval in minutes to retry failed uploads. + + rotate_interval_minutes: Interval in minutes to rotate logs. + + rotate_threshold_lines: Threshold in lines to rotate logs. + + rotate_threshold_mb: Threshold in MB to rotate logs. + + tags: Tags allow for dynamic decoration of logs by adding predefined fields to the log + format. These tags serve as customizable key-value pairs that can be included in + log entries to enhance context and readability. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/cdn/logs_uploader/policies", + body=await async_maybe_transform( + { + "date_format": date_format, + "description": description, + "escape_special_characters": escape_special_characters, + "field_delimiter": field_delimiter, + "field_separator": field_separator, + "fields": fields, + "file_name_template": file_name_template, + "format_type": format_type, + "include_empty_logs": include_empty_logs, + "include_shield_logs": include_shield_logs, + "log_sample_rate": log_sample_rate, + "name": name, + "retry_interval_minutes": retry_interval_minutes, + "rotate_interval_minutes": rotate_interval_minutes, + "rotate_threshold_lines": rotate_threshold_lines, + "rotate_threshold_mb": rotate_threshold_mb, + "tags": tags, + }, + policy_create_params.PolicyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderPolicy, + ) + + async def update( + self, + id: int, + *, + date_format: str | Omit = omit, + description: str | Omit = omit, + escape_special_characters: bool | Omit = omit, + field_delimiter: str | Omit = omit, + field_separator: str | Omit = omit, + fields: SequenceNotStr[str] | Omit = omit, + file_name_template: str | Omit = omit, + format_type: Literal["json", ""] | Omit = omit, + include_empty_logs: bool | Omit = omit, + include_shield_logs: bool | Omit = omit, + log_sample_rate: float | Omit = omit, + name: str | Omit = omit, + retry_interval_minutes: int | Omit = omit, + rotate_interval_minutes: int | Omit = omit, + rotate_threshold_lines: int | Omit = omit, + rotate_threshold_mb: Optional[int] | Omit = omit, + tags: Dict[str, str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderPolicy: + """ + Change logs uploader policy partially. + + Args: + date_format: Date format for logs. + + description: Description of the policy. + + escape_special_characters: When set to true, the service sanitizes string values by escaping characters + that may be unsafe for transport, logging, or downstream processing. + + The following categories of characters are escaped: + + - Control and non-printable characters + - Quotation marks and escape characters + - Characters outside the standard ASCII range + + The resulting output contains only printable ASCII characters. + + field_delimiter: Field delimiter for logs. + + field_separator: Field separator for logs. + + fields: List of fields to include in logs. + + file_name_template: Template for log file name. + + format_type: Format type for logs. + + Possible values: + + - **""** - empty, it means it will apply the format configurations from the + policy. + - **"json"** - output the logs as json lines. + + include_empty_logs: Include empty logs in the upload. + + include_shield_logs: Include logs from origin shielding in the upload. + + log_sample_rate: Sampling rate for logs. A value between 0 and 1 that determines the fraction of + log entries to collect. + + - **1** - collect all logs (default). + - **0.5** - collect approximately 50% of logs. + - **0** - collect no logs (effectively disables logging without removing the + policy). + + name: Name of the policy. + + retry_interval_minutes: Interval in minutes to retry failed uploads. + + rotate_interval_minutes: Interval in minutes to rotate logs. + + rotate_threshold_lines: Threshold in lines to rotate logs. + + rotate_threshold_mb: Threshold in MB to rotate logs. + + tags: Tags allow for dynamic decoration of logs by adding predefined fields to the log + format. These tags serve as customizable key-value pairs that can be included in + log entries to enhance context and readability. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/cdn/logs_uploader/policies/{id}", + body=await async_maybe_transform( + { + "date_format": date_format, + "description": description, + "escape_special_characters": escape_special_characters, + "field_delimiter": field_delimiter, + "field_separator": field_separator, + "fields": fields, + "file_name_template": file_name_template, + "format_type": format_type, + "include_empty_logs": include_empty_logs, + "include_shield_logs": include_shield_logs, + "log_sample_rate": log_sample_rate, + "name": name, + "retry_interval_minutes": retry_interval_minutes, + "rotate_interval_minutes": rotate_interval_minutes, + "rotate_threshold_lines": rotate_threshold_lines, + "rotate_threshold_mb": rotate_threshold_mb, + "tags": tags, + }, + policy_update_params.PolicyUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderPolicy, + ) + + async def list( + self, + *, + config_ids: Iterable[int] | Omit = omit, + search: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderPolicyList: + """ + Get list of logs uploader policies. + + Args: + config_ids: Filter by ids of related logs uploader configs that use given policy. + + search: Search by policy name or id. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/logs_uploader/policies", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "config_ids": config_ids, + "search": search, + }, + policy_list_params.PolicyListParams, + ), + ), + cast_to=LogsUploaderPolicyList, + ) + + async def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete the logs uploader policy from the system permanently. + + Notes: + + - **Irreversibility**: This action is irreversible. Once deleted, the logs + uploader policy cannot be recovered. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cdn/logs_uploader/policies/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderPolicy: + """ + Get information about logs uploader policy. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cdn/logs_uploader/policies/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderPolicy, + ) + + async def list_fields( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PolicyListFieldsResponse: + """Get list of available fields for logs uploader policy.""" + return await self._get( + "/cdn/logs_uploader/policies/fields", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyListFieldsResponse, + ) + + async def replace( + self, + id: int, + *, + date_format: str | Omit = omit, + description: str | Omit = omit, + escape_special_characters: bool | Omit = omit, + field_delimiter: str | Omit = omit, + field_separator: str | Omit = omit, + fields: SequenceNotStr[str] | Omit = omit, + file_name_template: str | Omit = omit, + format_type: Literal["json", ""] | Omit = omit, + include_empty_logs: bool | Omit = omit, + include_shield_logs: bool | Omit = omit, + log_sample_rate: float | Omit = omit, + name: str | Omit = omit, + retry_interval_minutes: int | Omit = omit, + rotate_interval_minutes: int | Omit = omit, + rotate_threshold_lines: int | Omit = omit, + rotate_threshold_mb: Optional[int] | Omit = omit, + tags: Dict[str, str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderPolicy: + """ + Change logs uploader policy. + + Args: + date_format: Date format for logs. + + description: Description of the policy. + + escape_special_characters: When set to true, the service sanitizes string values by escaping characters + that may be unsafe for transport, logging, or downstream processing. + + The following categories of characters are escaped: + + - Control and non-printable characters + - Quotation marks and escape characters + - Characters outside the standard ASCII range + + The resulting output contains only printable ASCII characters. + + field_delimiter: Field delimiter for logs. + + field_separator: Field separator for logs. + + fields: List of fields to include in logs. + + file_name_template: Template for log file name. + + format_type: Format type for logs. + + Possible values: + + - **""** - empty, it means it will apply the format configurations from the + policy. + - **"json"** - output the logs as json lines. + + include_empty_logs: Include empty logs in the upload. + + include_shield_logs: Include logs from origin shielding in the upload. + + log_sample_rate: Sampling rate for logs. A value between 0 and 1 that determines the fraction of + log entries to collect. + + - **1** - collect all logs (default). + - **0.5** - collect approximately 50% of logs. + - **0** - collect no logs (effectively disables logging without removing the + policy). + + name: Name of the policy. + + retry_interval_minutes: Interval in minutes to retry failed uploads. + + rotate_interval_minutes: Interval in minutes to rotate logs. + + rotate_threshold_lines: Threshold in lines to rotate logs. + + rotate_threshold_mb: Threshold in MB to rotate logs. + + tags: Tags allow for dynamic decoration of logs by adding predefined fields to the log + format. These tags serve as customizable key-value pairs that can be included in + log entries to enhance context and readability. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/cdn/logs_uploader/policies/{id}", + body=await async_maybe_transform( + { + "date_format": date_format, + "description": description, + "escape_special_characters": escape_special_characters, + "field_delimiter": field_delimiter, + "field_separator": field_separator, + "fields": fields, + "file_name_template": file_name_template, + "format_type": format_type, + "include_empty_logs": include_empty_logs, + "include_shield_logs": include_shield_logs, + "log_sample_rate": log_sample_rate, + "name": name, + "retry_interval_minutes": retry_interval_minutes, + "rotate_interval_minutes": rotate_interval_minutes, + "rotate_threshold_lines": rotate_threshold_lines, + "rotate_threshold_mb": rotate_threshold_mb, + "tags": tags, + }, + policy_replace_params.PolicyReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderPolicy, + ) + + +class PoliciesResourceWithRawResponse: + def __init__(self, policies: PoliciesResource) -> None: + self._policies = policies + + self.create = to_raw_response_wrapper( + policies.create, + ) + self.update = to_raw_response_wrapper( + policies.update, + ) + self.list = to_raw_response_wrapper( + policies.list, + ) + self.delete = to_raw_response_wrapper( + policies.delete, + ) + self.get = to_raw_response_wrapper( + policies.get, + ) + self.list_fields = to_raw_response_wrapper( + policies.list_fields, + ) + self.replace = to_raw_response_wrapper( + policies.replace, + ) + + +class AsyncPoliciesResourceWithRawResponse: + def __init__(self, policies: AsyncPoliciesResource) -> None: + self._policies = policies + + self.create = async_to_raw_response_wrapper( + policies.create, + ) + self.update = async_to_raw_response_wrapper( + policies.update, + ) + self.list = async_to_raw_response_wrapper( + policies.list, + ) + self.delete = async_to_raw_response_wrapper( + policies.delete, + ) + self.get = async_to_raw_response_wrapper( + policies.get, + ) + self.list_fields = async_to_raw_response_wrapper( + policies.list_fields, + ) + self.replace = async_to_raw_response_wrapper( + policies.replace, + ) + + +class PoliciesResourceWithStreamingResponse: + def __init__(self, policies: PoliciesResource) -> None: + self._policies = policies + + self.create = to_streamed_response_wrapper( + policies.create, + ) + self.update = to_streamed_response_wrapper( + policies.update, + ) + self.list = to_streamed_response_wrapper( + policies.list, + ) + self.delete = to_streamed_response_wrapper( + policies.delete, + ) + self.get = to_streamed_response_wrapper( + policies.get, + ) + self.list_fields = to_streamed_response_wrapper( + policies.list_fields, + ) + self.replace = to_streamed_response_wrapper( + policies.replace, + ) + + +class AsyncPoliciesResourceWithStreamingResponse: + def __init__(self, policies: AsyncPoliciesResource) -> None: + self._policies = policies + + self.create = async_to_streamed_response_wrapper( + policies.create, + ) + self.update = async_to_streamed_response_wrapper( + policies.update, + ) + self.list = async_to_streamed_response_wrapper( + policies.list, + ) + self.delete = async_to_streamed_response_wrapper( + policies.delete, + ) + self.get = async_to_streamed_response_wrapper( + policies.get, + ) + self.list_fields = async_to_streamed_response_wrapper( + policies.list_fields, + ) + self.replace = async_to_streamed_response_wrapper( + policies.replace, + ) diff --git a/src/gcore/resources/cdn/logs_uploader/targets.py b/src/gcore/resources/cdn/logs_uploader/targets.py new file mode 100644 index 00000000..c0eba285 --- /dev/null +++ b/src/gcore/resources/cdn/logs_uploader/targets.py @@ -0,0 +1,783 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cdn.logs_uploader import ( + target_list_params, + target_create_params, + target_update_params, + target_replace_params, +) +from ....types.cdn.logs_uploader_validation import LogsUploaderValidation +from ....types.cdn.logs_uploader.logs_uploader_target import LogsUploaderTarget +from ....types.cdn.logs_uploader.logs_uploader_target_list import LogsUploaderTargetList + +__all__ = ["TargetsResource", "AsyncTargetsResource"] + + +class TargetsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> TargetsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return TargetsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TargetsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return TargetsResourceWithStreamingResponse(self) + + def create( + self, + *, + config: target_create_params.Config, + storage_type: Literal["s3_gcore", "s3_amazon", "s3_oss", "s3_other", "s3_v1", "ftp", "sftp", "http"], + description: str | Omit = omit, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderTarget: + """ + Create logs uploader target. + + Args: + config: Config for specific storage type. + + storage_type: Type of storage for logs. + + description: Description of the target. + + name: Name of the target. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/cdn/logs_uploader/targets", + body=maybe_transform( + { + "config": config, + "storage_type": storage_type, + "description": description, + "name": name, + }, + target_create_params.TargetCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderTarget, + ) + + def update( + self, + id: int, + *, + config: target_update_params.Config | Omit = omit, + description: str | Omit = omit, + name: str | Omit = omit, + storage_type: Literal["s3_gcore", "s3_amazon", "s3_oss", "s3_other", "s3_v1", "ftp", "sftp", "http"] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderTarget: + """ + Change logs uploader target partially. + + Args: + config: Config for specific storage type. + + description: Description of the target. + + name: Name of the target. + + storage_type: Type of storage for logs. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/cdn/logs_uploader/targets/{id}", + body=maybe_transform( + { + "config": config, + "description": description, + "name": name, + "storage_type": storage_type, + }, + target_update_params.TargetUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderTarget, + ) + + def list( + self, + *, + config_ids: Iterable[int] | Omit = omit, + search: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderTargetList: + """ + Get list of logs uploader targets. + + Args: + config_ids: Filter by ids of related logs uploader configs that use given target. + + search: Search by target name or id. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/logs_uploader/targets", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "config_ids": config_ids, + "search": search, + }, + target_list_params.TargetListParams, + ), + ), + cast_to=LogsUploaderTargetList, + ) + + def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete the logs uploader target from the system permanently. + + Notes: + + - **Irreversibility**: This action is irreversible. Once deleted, the logs + uploader target cannot be recovered. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cdn/logs_uploader/targets/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderTarget: + """ + Get information about logs uploader target. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cdn/logs_uploader/targets/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderTarget, + ) + + def replace( + self, + id: int, + *, + config: target_replace_params.Config, + storage_type: Literal["s3_gcore", "s3_amazon", "s3_oss", "s3_other", "s3_v1", "ftp", "sftp", "http"], + description: str | Omit = omit, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderTarget: + """ + Change logs uploader target. + + Args: + config: Config for specific storage type. + + storage_type: Type of storage for logs. + + description: Description of the target. + + name: Name of the target. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/cdn/logs_uploader/targets/{id}", + body=maybe_transform( + { + "config": config, + "storage_type": storage_type, + "description": description, + "name": name, + }, + target_replace_params.TargetReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderTarget, + ) + + def validate( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderValidation: + """ + Validate logs uploader target. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/cdn/logs_uploader/targets/{id}/validate", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderValidation, + ) + + +class AsyncTargetsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncTargetsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncTargetsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTargetsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncTargetsResourceWithStreamingResponse(self) + + async def create( + self, + *, + config: target_create_params.Config, + storage_type: Literal["s3_gcore", "s3_amazon", "s3_oss", "s3_other", "s3_v1", "ftp", "sftp", "http"], + description: str | Omit = omit, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderTarget: + """ + Create logs uploader target. + + Args: + config: Config for specific storage type. + + storage_type: Type of storage for logs. + + description: Description of the target. + + name: Name of the target. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/cdn/logs_uploader/targets", + body=await async_maybe_transform( + { + "config": config, + "storage_type": storage_type, + "description": description, + "name": name, + }, + target_create_params.TargetCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderTarget, + ) + + async def update( + self, + id: int, + *, + config: target_update_params.Config | Omit = omit, + description: str | Omit = omit, + name: str | Omit = omit, + storage_type: Literal["s3_gcore", "s3_amazon", "s3_oss", "s3_other", "s3_v1", "ftp", "sftp", "http"] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderTarget: + """ + Change logs uploader target partially. + + Args: + config: Config for specific storage type. + + description: Description of the target. + + name: Name of the target. + + storage_type: Type of storage for logs. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/cdn/logs_uploader/targets/{id}", + body=await async_maybe_transform( + { + "config": config, + "description": description, + "name": name, + "storage_type": storage_type, + }, + target_update_params.TargetUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderTarget, + ) + + async def list( + self, + *, + config_ids: Iterable[int] | Omit = omit, + search: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderTargetList: + """ + Get list of logs uploader targets. + + Args: + config_ids: Filter by ids of related logs uploader configs that use given target. + + search: Search by target name or id. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/logs_uploader/targets", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "config_ids": config_ids, + "search": search, + }, + target_list_params.TargetListParams, + ), + ), + cast_to=LogsUploaderTargetList, + ) + + async def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete the logs uploader target from the system permanently. + + Notes: + + - **Irreversibility**: This action is irreversible. Once deleted, the logs + uploader target cannot be recovered. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cdn/logs_uploader/targets/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderTarget: + """ + Get information about logs uploader target. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cdn/logs_uploader/targets/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderTarget, + ) + + async def replace( + self, + id: int, + *, + config: target_replace_params.Config, + storage_type: Literal["s3_gcore", "s3_amazon", "s3_oss", "s3_other", "s3_v1", "ftp", "sftp", "http"], + description: str | Omit = omit, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderTarget: + """ + Change logs uploader target. + + Args: + config: Config for specific storage type. + + storage_type: Type of storage for logs. + + description: Description of the target. + + name: Name of the target. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/cdn/logs_uploader/targets/{id}", + body=await async_maybe_transform( + { + "config": config, + "storage_type": storage_type, + "description": description, + "name": name, + }, + target_replace_params.TargetReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderTarget, + ) + + async def validate( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsUploaderValidation: + """ + Validate logs uploader target. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/cdn/logs_uploader/targets/{id}/validate", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LogsUploaderValidation, + ) + + +class TargetsResourceWithRawResponse: + def __init__(self, targets: TargetsResource) -> None: + self._targets = targets + + self.create = to_raw_response_wrapper( + targets.create, + ) + self.update = to_raw_response_wrapper( + targets.update, + ) + self.list = to_raw_response_wrapper( + targets.list, + ) + self.delete = to_raw_response_wrapper( + targets.delete, + ) + self.get = to_raw_response_wrapper( + targets.get, + ) + self.replace = to_raw_response_wrapper( + targets.replace, + ) + self.validate = to_raw_response_wrapper( + targets.validate, + ) + + +class AsyncTargetsResourceWithRawResponse: + def __init__(self, targets: AsyncTargetsResource) -> None: + self._targets = targets + + self.create = async_to_raw_response_wrapper( + targets.create, + ) + self.update = async_to_raw_response_wrapper( + targets.update, + ) + self.list = async_to_raw_response_wrapper( + targets.list, + ) + self.delete = async_to_raw_response_wrapper( + targets.delete, + ) + self.get = async_to_raw_response_wrapper( + targets.get, + ) + self.replace = async_to_raw_response_wrapper( + targets.replace, + ) + self.validate = async_to_raw_response_wrapper( + targets.validate, + ) + + +class TargetsResourceWithStreamingResponse: + def __init__(self, targets: TargetsResource) -> None: + self._targets = targets + + self.create = to_streamed_response_wrapper( + targets.create, + ) + self.update = to_streamed_response_wrapper( + targets.update, + ) + self.list = to_streamed_response_wrapper( + targets.list, + ) + self.delete = to_streamed_response_wrapper( + targets.delete, + ) + self.get = to_streamed_response_wrapper( + targets.get, + ) + self.replace = to_streamed_response_wrapper( + targets.replace, + ) + self.validate = to_streamed_response_wrapper( + targets.validate, + ) + + +class AsyncTargetsResourceWithStreamingResponse: + def __init__(self, targets: AsyncTargetsResource) -> None: + self._targets = targets + + self.create = async_to_streamed_response_wrapper( + targets.create, + ) + self.update = async_to_streamed_response_wrapper( + targets.update, + ) + self.list = async_to_streamed_response_wrapper( + targets.list, + ) + self.delete = async_to_streamed_response_wrapper( + targets.delete, + ) + self.get = async_to_streamed_response_wrapper( + targets.get, + ) + self.replace = async_to_streamed_response_wrapper( + targets.replace, + ) + self.validate = async_to_streamed_response_wrapper( + targets.validate, + ) diff --git a/src/gcore/resources/cdn/metrics.py b/src/gcore/resources/cdn/metrics.py new file mode 100644 index 00000000..1f2297a4 --- /dev/null +++ b/src/gcore/resources/cdn/metrics.py @@ -0,0 +1,415 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cdn import metric_list_params +from ..._base_client import make_request_options +from ...types.cdn.cdn_metrics import CDNMetrics + +__all__ = ["MetricsResource", "AsyncMetricsResource"] + + +class MetricsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> MetricsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return MetricsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MetricsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return MetricsResourceWithStreamingResponse(self) + + def list( + self, + *, + from_: str, + metrics: SequenceNotStr[str], + to: str, + filter_by: Iterable[metric_list_params.FilterBy] | Omit = omit, + granularity: str | Omit = omit, + group_by: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNMetrics: + """ + Get CDN metrics + + Args: + from_: Beginning period to fetch metrics (ISO 8601/RFC 3339 format, UTC.) + + Examples: + + - 2021-06-14T00:00:00Z + - 2021-06-14T00:00:00.000Z + + The total number of points, which is determined as the difference between "from" + and "to" divided by "granularity", cannot exceed 1440. Exception: "speed" + metrics are limited to 72 points. + + metrics: + Possible values: + + - **`edge_bandwidth`** - Bandwidth from client to CDN (bit/s.) + - **`edge_requests`** - Number of requests per interval (requests/s.) + - **`edge_requests_total`** - Total number of requests per interval. + - **`edge_status_1xx`** - Number of 1xx status codes from edge. + - **`edge_status_200`** - Number of 200 status codes from edge. + - **`edge_status_204`** - Number of 204 status codes from edge. + - **`edge_status_206`** - Number of 206 status codes from edge. + - **`edge_status_2xx`** - Number of 2xx status codes from edge. + - **`edge_status_301`** - Number of 301 status codes from edge. + - **`edge_status_302`** - Number of 302 status codes from edge. + - **`edge_status_304`** - Number of 304 status codes from edge. + - **`edge_status_3xx`** - Number of 3xx status codes from edge. + - **`edge_status_400`** - Number of 400 status codes from edge. + - **`edge_status_401`** - Number of 401 status codes from edge. + - **`edge_status_403`** - Number of 403 status codes from edge. + - **`edge_status_404`** - Number of 404 status codes from edge. + - **`edge_status_416`** - Number of 416 status codes from edge. + - **`edge_status_429`** - Number of 429 status codes from edge. + - **`edge_status_4xx`** - Number of 4xx status codes from edge. + - **`edge_status_500`** - Number of 500 status codes from edge. + - **`edge_status_501`** - Number of 501 status codes from edge. + - **`edge_status_502`** - Number of 502 status codes from edge. + - **`edge_status_503`** - Number of 503 status codes from edge. + - **`edge_status_504`** - Number of 504 status codes from edge. + - **`edge_status_505`** - Number of 505 status codes from edge. + - **`edge_status_5xx`** - Number of 5xx status codes from edge. + - **`edge_hit_ratio`** - Percent of cache hits (0.0 - 1.0). + - **`edge_hit_bytes`** - Number of bytes sent back when cache hits. + - **`origin_bandwidth`** - Bandwidth from CDN to Origin (bit/s.) + - **`origin_requests`** - Number of requests per interval (requests/s.) + - **`origin_status_1xx`** - Number of 1xx status from origin. + - **`origin_status_200`** - Number of 200 status from origin. + - **`origin_status_204`** - Number of 204 status from origin. + - **`origin_status_206`** - Number of 206 status from origin. + - **`origin_status_2xx`** - Number of 2xx status from origin. + - **`origin_status_301`** - Number of 301 status from origin. + - **`origin_status_302`** - Number of 302 status from origin. + - **`origin_status_304`** - Number of 304 status from origin. + - **`origin_status_3xx`** - Number of 3xx status from origin. + - **`origin_status_400`** - Number of 400 status from origin. + - **`origin_status_401`** - Number of 401 status from origin. + - **`origin_status_403`** - Number of 403 status from origin. + - **`origin_status_404`** - Number of 404 status from origin. + - **`origin_status_416`** - Number of 416 status from origin. + - **`origin_status_429`** - Number of 426 status from origin. + - **`origin_status_4xx`** - Number of 4xx status from origin. + - **`origin_status_500`** - Number of 500 status from origin. + - **`origin_status_501`** - Number of 501 status from origin. + - **`origin_status_502`** - Number of 502 status from origin. + - **`origin_status_503`** - Number of 503 status from origin. + - **`origin_status_504`** - Number of 504 status from origin. + - **`origin_status_505`** - Number of 505 status from origin. + - **`origin_status_5xx`** - Number of 5xx status from origin. + - **`edge_download_speed`** - Download speed from edge in KB/s (includes only + requests that status was in the range [200, 300].) + - **`origin_download_speed`** - Download speed from origin in KB/s (includes + only requests that status was in the range [200, 300].) + + to: Specifies ending period to fetch metrics (ISO 8601/RFC 3339 format, UTC) + + Examples: + + - 2021-06-15T00:00:00Z + - 2021-06-15T00:00:00.000Z + + The total number of points, which is determined as the difference between "from" + and "to" divided by "granularity", cannot exceed 1440. Exception: "speed" + metrics are limited to 72 points. + + filter_by: Each item represents one filter statement. + + granularity: Duration of the time blocks into which the data is divided. The value must + correspond to the ISO 8601 period format. + + Examples: + + - P1D + - PT5M + + Notes: + + - The total number of points, which is determined as the difference between + "from" and "to" divided by "granularity", cannot exceed 1440. Exception: + "speed" metrics are limited to 72 points. + - For "speed" metrics the value must be a multiple of 5. + + group_by: Output data grouping. + + Possible values: + + - **resource** - Data is grouped by CDN resource. + - **cname** - Data is grouped by common names. + - **region** – Data is grouped by regions (continents.) Available for "speed" + metrics only. + - **isp** - Data is grouped by ISP names. Available for "speed" metrics only. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/cdn/advanced/v1/metrics", + body=maybe_transform( + { + "from_": from_, + "metrics": metrics, + "to": to, + "filter_by": filter_by, + "granularity": granularity, + "group_by": group_by, + }, + metric_list_params.MetricListParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNMetrics, + ) + + +class AsyncMetricsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncMetricsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncMetricsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMetricsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncMetricsResourceWithStreamingResponse(self) + + async def list( + self, + *, + from_: str, + metrics: SequenceNotStr[str], + to: str, + filter_by: Iterable[metric_list_params.FilterBy] | Omit = omit, + granularity: str | Omit = omit, + group_by: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CDNMetrics: + """ + Get CDN metrics + + Args: + from_: Beginning period to fetch metrics (ISO 8601/RFC 3339 format, UTC.) + + Examples: + + - 2021-06-14T00:00:00Z + - 2021-06-14T00:00:00.000Z + + The total number of points, which is determined as the difference between "from" + and "to" divided by "granularity", cannot exceed 1440. Exception: "speed" + metrics are limited to 72 points. + + metrics: + Possible values: + + - **`edge_bandwidth`** - Bandwidth from client to CDN (bit/s.) + - **`edge_requests`** - Number of requests per interval (requests/s.) + - **`edge_requests_total`** - Total number of requests per interval. + - **`edge_status_1xx`** - Number of 1xx status codes from edge. + - **`edge_status_200`** - Number of 200 status codes from edge. + - **`edge_status_204`** - Number of 204 status codes from edge. + - **`edge_status_206`** - Number of 206 status codes from edge. + - **`edge_status_2xx`** - Number of 2xx status codes from edge. + - **`edge_status_301`** - Number of 301 status codes from edge. + - **`edge_status_302`** - Number of 302 status codes from edge. + - **`edge_status_304`** - Number of 304 status codes from edge. + - **`edge_status_3xx`** - Number of 3xx status codes from edge. + - **`edge_status_400`** - Number of 400 status codes from edge. + - **`edge_status_401`** - Number of 401 status codes from edge. + - **`edge_status_403`** - Number of 403 status codes from edge. + - **`edge_status_404`** - Number of 404 status codes from edge. + - **`edge_status_416`** - Number of 416 status codes from edge. + - **`edge_status_429`** - Number of 429 status codes from edge. + - **`edge_status_4xx`** - Number of 4xx status codes from edge. + - **`edge_status_500`** - Number of 500 status codes from edge. + - **`edge_status_501`** - Number of 501 status codes from edge. + - **`edge_status_502`** - Number of 502 status codes from edge. + - **`edge_status_503`** - Number of 503 status codes from edge. + - **`edge_status_504`** - Number of 504 status codes from edge. + - **`edge_status_505`** - Number of 505 status codes from edge. + - **`edge_status_5xx`** - Number of 5xx status codes from edge. + - **`edge_hit_ratio`** - Percent of cache hits (0.0 - 1.0). + - **`edge_hit_bytes`** - Number of bytes sent back when cache hits. + - **`origin_bandwidth`** - Bandwidth from CDN to Origin (bit/s.) + - **`origin_requests`** - Number of requests per interval (requests/s.) + - **`origin_status_1xx`** - Number of 1xx status from origin. + - **`origin_status_200`** - Number of 200 status from origin. + - **`origin_status_204`** - Number of 204 status from origin. + - **`origin_status_206`** - Number of 206 status from origin. + - **`origin_status_2xx`** - Number of 2xx status from origin. + - **`origin_status_301`** - Number of 301 status from origin. + - **`origin_status_302`** - Number of 302 status from origin. + - **`origin_status_304`** - Number of 304 status from origin. + - **`origin_status_3xx`** - Number of 3xx status from origin. + - **`origin_status_400`** - Number of 400 status from origin. + - **`origin_status_401`** - Number of 401 status from origin. + - **`origin_status_403`** - Number of 403 status from origin. + - **`origin_status_404`** - Number of 404 status from origin. + - **`origin_status_416`** - Number of 416 status from origin. + - **`origin_status_429`** - Number of 426 status from origin. + - **`origin_status_4xx`** - Number of 4xx status from origin. + - **`origin_status_500`** - Number of 500 status from origin. + - **`origin_status_501`** - Number of 501 status from origin. + - **`origin_status_502`** - Number of 502 status from origin. + - **`origin_status_503`** - Number of 503 status from origin. + - **`origin_status_504`** - Number of 504 status from origin. + - **`origin_status_505`** - Number of 505 status from origin. + - **`origin_status_5xx`** - Number of 5xx status from origin. + - **`edge_download_speed`** - Download speed from edge in KB/s (includes only + requests that status was in the range [200, 300].) + - **`origin_download_speed`** - Download speed from origin in KB/s (includes + only requests that status was in the range [200, 300].) + + to: Specifies ending period to fetch metrics (ISO 8601/RFC 3339 format, UTC) + + Examples: + + - 2021-06-15T00:00:00Z + - 2021-06-15T00:00:00.000Z + + The total number of points, which is determined as the difference between "from" + and "to" divided by "granularity", cannot exceed 1440. Exception: "speed" + metrics are limited to 72 points. + + filter_by: Each item represents one filter statement. + + granularity: Duration of the time blocks into which the data is divided. The value must + correspond to the ISO 8601 period format. + + Examples: + + - P1D + - PT5M + + Notes: + + - The total number of points, which is determined as the difference between + "from" and "to" divided by "granularity", cannot exceed 1440. Exception: + "speed" metrics are limited to 72 points. + - For "speed" metrics the value must be a multiple of 5. + + group_by: Output data grouping. + + Possible values: + + - **resource** - Data is grouped by CDN resource. + - **cname** - Data is grouped by common names. + - **region** – Data is grouped by regions (continents.) Available for "speed" + metrics only. + - **isp** - Data is grouped by ISP names. Available for "speed" metrics only. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/cdn/advanced/v1/metrics", + body=await async_maybe_transform( + { + "from_": from_, + "metrics": metrics, + "to": to, + "filter_by": filter_by, + "granularity": granularity, + "group_by": group_by, + }, + metric_list_params.MetricListParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CDNMetrics, + ) + + +class MetricsResourceWithRawResponse: + def __init__(self, metrics: MetricsResource) -> None: + self._metrics = metrics + + self.list = to_raw_response_wrapper( + metrics.list, + ) + + +class AsyncMetricsResourceWithRawResponse: + def __init__(self, metrics: AsyncMetricsResource) -> None: + self._metrics = metrics + + self.list = async_to_raw_response_wrapper( + metrics.list, + ) + + +class MetricsResourceWithStreamingResponse: + def __init__(self, metrics: MetricsResource) -> None: + self._metrics = metrics + + self.list = to_streamed_response_wrapper( + metrics.list, + ) + + +class AsyncMetricsResourceWithStreamingResponse: + def __init__(self, metrics: AsyncMetricsResource) -> None: + self._metrics = metrics + + self.list = async_to_streamed_response_wrapper( + metrics.list, + ) diff --git a/src/gcore/resources/cdn/network_capacity.py b/src/gcore/resources/cdn/network_capacity.py new file mode 100644 index 00000000..870849d3 --- /dev/null +++ b/src/gcore/resources/cdn/network_capacity.py @@ -0,0 +1,135 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.cdn.network_capacity import NetworkCapacity + +__all__ = ["NetworkCapacityResource", "AsyncNetworkCapacityResource"] + + +class NetworkCapacityResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> NetworkCapacityResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return NetworkCapacityResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> NetworkCapacityResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return NetworkCapacityResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NetworkCapacity: + """Get network capacity per country.""" + return self._get( + "/cdn/advanced/v1/capacity", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NetworkCapacity, + ) + + +class AsyncNetworkCapacityResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncNetworkCapacityResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncNetworkCapacityResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncNetworkCapacityResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncNetworkCapacityResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NetworkCapacity: + """Get network capacity per country.""" + return await self._get( + "/cdn/advanced/v1/capacity", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NetworkCapacity, + ) + + +class NetworkCapacityResourceWithRawResponse: + def __init__(self, network_capacity: NetworkCapacityResource) -> None: + self._network_capacity = network_capacity + + self.list = to_raw_response_wrapper( + network_capacity.list, + ) + + +class AsyncNetworkCapacityResourceWithRawResponse: + def __init__(self, network_capacity: AsyncNetworkCapacityResource) -> None: + self._network_capacity = network_capacity + + self.list = async_to_raw_response_wrapper( + network_capacity.list, + ) + + +class NetworkCapacityResourceWithStreamingResponse: + def __init__(self, network_capacity: NetworkCapacityResource) -> None: + self._network_capacity = network_capacity + + self.list = to_streamed_response_wrapper( + network_capacity.list, + ) + + +class AsyncNetworkCapacityResourceWithStreamingResponse: + def __init__(self, network_capacity: AsyncNetworkCapacityResource) -> None: + self._network_capacity = network_capacity + + self.list = async_to_streamed_response_wrapper( + network_capacity.list, + ) diff --git a/src/gcore/resources/cdn/origin_groups.py b/src/gcore/resources/cdn/origin_groups.py new file mode 100644 index 00000000..fd8beae5 --- /dev/null +++ b/src/gcore/resources/cdn/origin_groups.py @@ -0,0 +1,1476 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Any, Iterable, cast +from typing_extensions import overload + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import required_args, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cdn import ( + origin_group_list_params, + origin_group_create_params, + origin_group_update_params, + origin_group_replace_params, +) +from ..._base_client import make_request_options +from ...types.cdn.origin_groups import OriginGroups +from ...types.cdn.origin_groups_list import OriginGroupsList + +__all__ = ["OriginGroupsResource", "AsyncOriginGroupsResource"] + + +class OriginGroupsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> OriginGroupsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return OriginGroupsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> OriginGroupsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return OriginGroupsResourceWithStreamingResponse(self) + + @overload + def create( + self, + *, + name: str, + sources: Iterable[origin_group_create_params.NoneAuthSource], + auth_type: str | Omit = omit, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + use_next: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Create an origin group with one or more origin sources. + + Args: + name: Origin group name. + + sources: List of origin sources in the origin group. + + auth_type: Origin authentication type. + + Possible values: + + - **none** - Used for public origins. + - **awsSignatureV4** - Used for S3 storage. + + proxy_next_upstream: Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + + use_next: Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + auth: origin_group_create_params.AwsSignatureV4Auth, + auth_type: str, + name: str, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + use_next: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Create an origin group with one or more origin sources. + + Args: + auth: Credentials to access the private bucket. + + auth_type: Authentication type. + + **awsSignatureV4** value is used for S3 storage. + + name: Origin group name. + + proxy_next_upstream: Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + + use_next: Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["name", "sources"], ["auth", "auth_type", "name"]) + def create( + self, + *, + name: str, + sources: Iterable[origin_group_create_params.NoneAuthSource] | Omit = omit, + auth_type: str | Omit = omit, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + use_next: bool | Omit = omit, + auth: origin_group_create_params.AwsSignatureV4Auth | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + return cast( + OriginGroups, + self._post( + "/cdn/origin_groups", + body=maybe_transform( + { + "name": name, + "sources": sources, + "auth_type": auth_type, + "proxy_next_upstream": proxy_next_upstream, + "use_next": use_next, + "auth": auth, + }, + origin_group_create_params.OriginGroupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, OriginGroups), # Union types cannot be passed in as arguments in the type system + ), + ) + + @overload + def update( + self, + origin_group_id: int, + *, + name: str, + auth_type: str | Omit = omit, + path: str | Omit = omit, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + sources: Iterable[origin_group_update_params.NoneAuthSource] | Omit = omit, + use_next: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Change origin group + + Args: + name: Origin group name. + + auth_type: Origin authentication type. + + Possible values: + + - **none** - Used for public origins. + - **awsSignatureV4** - Used for S3 storage. + + path: Parameter is **deprecated**. + + proxy_next_upstream: Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + + sources: List of origin sources in the origin group. + + use_next: Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def update( + self, + origin_group_id: int, + *, + auth: origin_group_update_params.AwsSignatureV4Auth | Omit = omit, + auth_type: str | Omit = omit, + name: str | Omit = omit, + path: str | Omit = omit, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + use_next: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Change origin group + + Args: + auth: Credentials to access the private bucket. + + auth_type: Authentication type. + + **awsSignatureV4** value is used for S3 storage. + + name: Origin group name. + + path: Parameter is **deprecated**. + + proxy_next_upstream: Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + + use_next: Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + def update( + self, + origin_group_id: int, + *, + name: str | Omit = omit, + auth_type: str | Omit = omit, + path: str | Omit = omit, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + sources: Iterable[origin_group_update_params.NoneAuthSource] | Omit = omit, + use_next: bool | Omit = omit, + auth: origin_group_update_params.AwsSignatureV4Auth | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + return cast( + OriginGroups, + self._patch( + f"/cdn/origin_groups/{origin_group_id}", + body=maybe_transform( + { + "name": name, + "auth_type": auth_type, + "path": path, + "proxy_next_upstream": proxy_next_upstream, + "sources": sources, + "use_next": use_next, + "auth": auth, + }, + origin_group_update_params.OriginGroupUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, OriginGroups), # Union types cannot be passed in as arguments in the type system + ), + ) + + def list( + self, + *, + has_related_resources: bool | Omit = omit, + name: str | Omit = omit, + sources: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroupsList: + """ + Get all origin groups and related origin sources. + + Args: + has_related_resources: Defines whether the origin group has related CDN resources. + + Possible values: + + - **true** – Origin group has related CDN resources. + - **false** – Origin group does not have related CDN resources. + + name: Origin group name. + + sources: Origin sources (IP addresses or domains) in the origin group. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/origin_groups", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "has_related_resources": has_related_resources, + "name": name, + "sources": sources, + }, + origin_group_list_params.OriginGroupListParams, + ), + ), + cast_to=OriginGroupsList, + ) + + def delete( + self, + origin_group_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete origin group + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cdn/origin_groups/{origin_group_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + origin_group_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Get origin group details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return cast( + OriginGroups, + self._get( + f"/cdn/origin_groups/{origin_group_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, OriginGroups), # Union types cannot be passed in as arguments in the type system + ), + ) + + @overload + def replace( + self, + origin_group_id: int, + *, + auth_type: str, + name: str, + path: str, + sources: Iterable[origin_group_replace_params.NoneAuthSource], + use_next: bool, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Change origin group + + Args: + auth_type: Origin authentication type. + + Possible values: + + - **none** - Used for public origins. + - **awsSignatureV4** - Used for S3 storage. + + name: Origin group name. + + path: Parameter is **deprecated**. + + sources: List of origin sources in the origin group. + + use_next: Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + + proxy_next_upstream: Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def replace( + self, + origin_group_id: int, + *, + auth: origin_group_replace_params.AwsSignatureV4Auth, + auth_type: str, + name: str, + path: str, + use_next: bool, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Change origin group + + Args: + auth: Credentials to access the private bucket. + + auth_type: Authentication type. + + **awsSignatureV4** value is used for S3 storage. + + name: Origin group name. + + path: Parameter is **deprecated**. + + use_next: Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + + proxy_next_upstream: Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args( + ["auth_type", "name", "path", "sources", "use_next"], ["auth", "auth_type", "name", "path", "use_next"] + ) + def replace( + self, + origin_group_id: int, + *, + auth_type: str, + name: str, + path: str, + sources: Iterable[origin_group_replace_params.NoneAuthSource] | Omit = omit, + use_next: bool, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + auth: origin_group_replace_params.AwsSignatureV4Auth | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + return cast( + OriginGroups, + self._put( + f"/cdn/origin_groups/{origin_group_id}", + body=maybe_transform( + { + "auth_type": auth_type, + "name": name, + "path": path, + "sources": sources, + "use_next": use_next, + "proxy_next_upstream": proxy_next_upstream, + "auth": auth, + }, + origin_group_replace_params.OriginGroupReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, OriginGroups), # Union types cannot be passed in as arguments in the type system + ), + ) + + +class AsyncOriginGroupsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncOriginGroupsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncOriginGroupsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncOriginGroupsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncOriginGroupsResourceWithStreamingResponse(self) + + @overload + async def create( + self, + *, + name: str, + sources: Iterable[origin_group_create_params.NoneAuthSource], + auth_type: str | Omit = omit, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + use_next: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Create an origin group with one or more origin sources. + + Args: + name: Origin group name. + + sources: List of origin sources in the origin group. + + auth_type: Origin authentication type. + + Possible values: + + - **none** - Used for public origins. + - **awsSignatureV4** - Used for S3 storage. + + proxy_next_upstream: Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + + use_next: Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + auth: origin_group_create_params.AwsSignatureV4Auth, + auth_type: str, + name: str, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + use_next: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Create an origin group with one or more origin sources. + + Args: + auth: Credentials to access the private bucket. + + auth_type: Authentication type. + + **awsSignatureV4** value is used for S3 storage. + + name: Origin group name. + + proxy_next_upstream: Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + + use_next: Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["name", "sources"], ["auth", "auth_type", "name"]) + async def create( + self, + *, + name: str, + sources: Iterable[origin_group_create_params.NoneAuthSource] | Omit = omit, + auth_type: str | Omit = omit, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + use_next: bool | Omit = omit, + auth: origin_group_create_params.AwsSignatureV4Auth | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + return cast( + OriginGroups, + await self._post( + "/cdn/origin_groups", + body=await async_maybe_transform( + { + "name": name, + "sources": sources, + "auth_type": auth_type, + "proxy_next_upstream": proxy_next_upstream, + "use_next": use_next, + "auth": auth, + }, + origin_group_create_params.OriginGroupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, OriginGroups), # Union types cannot be passed in as arguments in the type system + ), + ) + + @overload + async def update( + self, + origin_group_id: int, + *, + name: str, + auth_type: str | Omit = omit, + path: str | Omit = omit, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + sources: Iterable[origin_group_update_params.NoneAuthSource] | Omit = omit, + use_next: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Change origin group + + Args: + name: Origin group name. + + auth_type: Origin authentication type. + + Possible values: + + - **none** - Used for public origins. + - **awsSignatureV4** - Used for S3 storage. + + path: Parameter is **deprecated**. + + proxy_next_upstream: Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + + sources: List of origin sources in the origin group. + + use_next: Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def update( + self, + origin_group_id: int, + *, + auth: origin_group_update_params.AwsSignatureV4Auth | Omit = omit, + auth_type: str | Omit = omit, + name: str | Omit = omit, + path: str | Omit = omit, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + use_next: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Change origin group + + Args: + auth: Credentials to access the private bucket. + + auth_type: Authentication type. + + **awsSignatureV4** value is used for S3 storage. + + name: Origin group name. + + path: Parameter is **deprecated**. + + proxy_next_upstream: Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + + use_next: Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + async def update( + self, + origin_group_id: int, + *, + name: str | Omit = omit, + auth_type: str | Omit = omit, + path: str | Omit = omit, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + sources: Iterable[origin_group_update_params.NoneAuthSource] | Omit = omit, + use_next: bool | Omit = omit, + auth: origin_group_update_params.AwsSignatureV4Auth | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + return cast( + OriginGroups, + await self._patch( + f"/cdn/origin_groups/{origin_group_id}", + body=await async_maybe_transform( + { + "name": name, + "auth_type": auth_type, + "path": path, + "proxy_next_upstream": proxy_next_upstream, + "sources": sources, + "use_next": use_next, + "auth": auth, + }, + origin_group_update_params.OriginGroupUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, OriginGroups), # Union types cannot be passed in as arguments in the type system + ), + ) + + async def list( + self, + *, + has_related_resources: bool | Omit = omit, + name: str | Omit = omit, + sources: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroupsList: + """ + Get all origin groups and related origin sources. + + Args: + has_related_resources: Defines whether the origin group has related CDN resources. + + Possible values: + + - **true** – Origin group has related CDN resources. + - **false** – Origin group does not have related CDN resources. + + name: Origin group name. + + sources: Origin sources (IP addresses or domains) in the origin group. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/origin_groups", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "has_related_resources": has_related_resources, + "name": name, + "sources": sources, + }, + origin_group_list_params.OriginGroupListParams, + ), + ), + cast_to=OriginGroupsList, + ) + + async def delete( + self, + origin_group_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete origin group + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cdn/origin_groups/{origin_group_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + origin_group_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Get origin group details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return cast( + OriginGroups, + await self._get( + f"/cdn/origin_groups/{origin_group_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, OriginGroups), # Union types cannot be passed in as arguments in the type system + ), + ) + + @overload + async def replace( + self, + origin_group_id: int, + *, + auth_type: str, + name: str, + path: str, + sources: Iterable[origin_group_replace_params.NoneAuthSource], + use_next: bool, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Change origin group + + Args: + auth_type: Origin authentication type. + + Possible values: + + - **none** - Used for public origins. + - **awsSignatureV4** - Used for S3 storage. + + name: Origin group name. + + path: Parameter is **deprecated**. + + sources: List of origin sources in the origin group. + + use_next: Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + + proxy_next_upstream: Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def replace( + self, + origin_group_id: int, + *, + auth: origin_group_replace_params.AwsSignatureV4Auth, + auth_type: str, + name: str, + path: str, + use_next: bool, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + """ + Change origin group + + Args: + auth: Credentials to access the private bucket. + + auth_type: Authentication type. + + **awsSignatureV4** value is used for S3 storage. + + name: Origin group name. + + path: Parameter is **deprecated**. + + use_next: Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + + proxy_next_upstream: Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args( + ["auth_type", "name", "path", "sources", "use_next"], ["auth", "auth_type", "name", "path", "use_next"] + ) + async def replace( + self, + origin_group_id: int, + *, + auth_type: str, + name: str, + path: str, + sources: Iterable[origin_group_replace_params.NoneAuthSource] | Omit = omit, + use_next: bool, + proxy_next_upstream: SequenceNotStr[str] | Omit = omit, + auth: origin_group_replace_params.AwsSignatureV4Auth | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OriginGroups: + return cast( + OriginGroups, + await self._put( + f"/cdn/origin_groups/{origin_group_id}", + body=await async_maybe_transform( + { + "auth_type": auth_type, + "name": name, + "path": path, + "sources": sources, + "use_next": use_next, + "proxy_next_upstream": proxy_next_upstream, + "auth": auth, + }, + origin_group_replace_params.OriginGroupReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, OriginGroups), # Union types cannot be passed in as arguments in the type system + ), + ) + + +class OriginGroupsResourceWithRawResponse: + def __init__(self, origin_groups: OriginGroupsResource) -> None: + self._origin_groups = origin_groups + + self.create = to_raw_response_wrapper( + origin_groups.create, + ) + self.update = to_raw_response_wrapper( + origin_groups.update, + ) + self.list = to_raw_response_wrapper( + origin_groups.list, + ) + self.delete = to_raw_response_wrapper( + origin_groups.delete, + ) + self.get = to_raw_response_wrapper( + origin_groups.get, + ) + self.replace = to_raw_response_wrapper( + origin_groups.replace, + ) + + +class AsyncOriginGroupsResourceWithRawResponse: + def __init__(self, origin_groups: AsyncOriginGroupsResource) -> None: + self._origin_groups = origin_groups + + self.create = async_to_raw_response_wrapper( + origin_groups.create, + ) + self.update = async_to_raw_response_wrapper( + origin_groups.update, + ) + self.list = async_to_raw_response_wrapper( + origin_groups.list, + ) + self.delete = async_to_raw_response_wrapper( + origin_groups.delete, + ) + self.get = async_to_raw_response_wrapper( + origin_groups.get, + ) + self.replace = async_to_raw_response_wrapper( + origin_groups.replace, + ) + + +class OriginGroupsResourceWithStreamingResponse: + def __init__(self, origin_groups: OriginGroupsResource) -> None: + self._origin_groups = origin_groups + + self.create = to_streamed_response_wrapper( + origin_groups.create, + ) + self.update = to_streamed_response_wrapper( + origin_groups.update, + ) + self.list = to_streamed_response_wrapper( + origin_groups.list, + ) + self.delete = to_streamed_response_wrapper( + origin_groups.delete, + ) + self.get = to_streamed_response_wrapper( + origin_groups.get, + ) + self.replace = to_streamed_response_wrapper( + origin_groups.replace, + ) + + +class AsyncOriginGroupsResourceWithStreamingResponse: + def __init__(self, origin_groups: AsyncOriginGroupsResource) -> None: + self._origin_groups = origin_groups + + self.create = async_to_streamed_response_wrapper( + origin_groups.create, + ) + self.update = async_to_streamed_response_wrapper( + origin_groups.update, + ) + self.list = async_to_streamed_response_wrapper( + origin_groups.list, + ) + self.delete = async_to_streamed_response_wrapper( + origin_groups.delete, + ) + self.get = async_to_streamed_response_wrapper( + origin_groups.get, + ) + self.replace = async_to_streamed_response_wrapper( + origin_groups.replace, + ) diff --git a/src/gcore/resources/cdn/rule_templates.py b/src/gcore/resources/cdn/rule_templates.py new file mode 100644 index 00000000..326b7811 --- /dev/null +++ b/src/gcore/resources/cdn/rule_templates.py @@ -0,0 +1,859 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cdn import rule_template_create_params, rule_template_update_params, rule_template_replace_params +from ..._base_client import make_request_options +from ...types.cdn.rule_template import RuleTemplate +from ...types.cdn.rule_template_list import RuleTemplateList + +__all__ = ["RuleTemplatesResource", "AsyncRuleTemplatesResource"] + + +class RuleTemplatesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RuleTemplatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return RuleTemplatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RuleTemplatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return RuleTemplatesResourceWithStreamingResponse(self) + + def create( + self, + *, + rule: str, + rule_type: int, + name: str | Omit = omit, + options: rule_template_create_params.Options | Omit = omit, + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleTemplate: + """ + Create rule template + + Args: + rule: Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + + rule_type: Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + + name: Rule template name. + + options: List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + + override_origin_protocol: Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + + weight: Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/cdn/resources/rule_templates", + body=maybe_transform( + { + "rule": rule, + "rule_type": rule_type, + "name": name, + "options": options, + "override_origin_protocol": override_origin_protocol, + "weight": weight, + }, + rule_template_create_params.RuleTemplateCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RuleTemplate, + ) + + def update( + self, + rule_template_id: int, + *, + name: str | Omit = omit, + options: rule_template_update_params.Options | Omit = omit, + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] | Omit = omit, + rule: str | Omit = omit, + rule_type: int | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleTemplate: + """ + Change rule template + + Args: + name: Rule template name. + + options: List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + + override_origin_protocol: Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + + rule: Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + + rule_type: Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + + weight: Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/cdn/resources/rule_templates/{rule_template_id}", + body=maybe_transform( + { + "name": name, + "options": options, + "override_origin_protocol": override_origin_protocol, + "rule": rule, + "rule_type": rule_type, + "weight": weight, + }, + rule_template_update_params.RuleTemplateUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RuleTemplate, + ) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleTemplateList: + """Get rule templates list""" + return self._get( + "/cdn/resources/rule_templates", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RuleTemplateList, + ) + + def delete( + self, + rule_template_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete rule template + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cdn/resources/rule_templates/{rule_template_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + rule_template_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleTemplate: + """ + Get rule template details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cdn/resources/rule_templates/{rule_template_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RuleTemplate, + ) + + def replace( + self, + rule_template_id: int, + *, + rule: str, + rule_type: int, + name: str | Omit = omit, + options: rule_template_replace_params.Options | Omit = omit, + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleTemplate: + """ + Change rule template + + Args: + rule: Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + + rule_type: Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + + name: Rule template name. + + options: List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + + override_origin_protocol: Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + + weight: Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/cdn/resources/rule_templates/{rule_template_id}", + body=maybe_transform( + { + "rule": rule, + "rule_type": rule_type, + "name": name, + "options": options, + "override_origin_protocol": override_origin_protocol, + "weight": weight, + }, + rule_template_replace_params.RuleTemplateReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RuleTemplate, + ) + + +class AsyncRuleTemplatesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRuleTemplatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncRuleTemplatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRuleTemplatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncRuleTemplatesResourceWithStreamingResponse(self) + + async def create( + self, + *, + rule: str, + rule_type: int, + name: str | Omit = omit, + options: rule_template_create_params.Options | Omit = omit, + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleTemplate: + """ + Create rule template + + Args: + rule: Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + + rule_type: Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + + name: Rule template name. + + options: List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + + override_origin_protocol: Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + + weight: Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/cdn/resources/rule_templates", + body=await async_maybe_transform( + { + "rule": rule, + "rule_type": rule_type, + "name": name, + "options": options, + "override_origin_protocol": override_origin_protocol, + "weight": weight, + }, + rule_template_create_params.RuleTemplateCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RuleTemplate, + ) + + async def update( + self, + rule_template_id: int, + *, + name: str | Omit = omit, + options: rule_template_update_params.Options | Omit = omit, + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] | Omit = omit, + rule: str | Omit = omit, + rule_type: int | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleTemplate: + """ + Change rule template + + Args: + name: Rule template name. + + options: List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + + override_origin_protocol: Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + + rule: Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + + rule_type: Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + + weight: Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/cdn/resources/rule_templates/{rule_template_id}", + body=await async_maybe_transform( + { + "name": name, + "options": options, + "override_origin_protocol": override_origin_protocol, + "rule": rule, + "rule_type": rule_type, + "weight": weight, + }, + rule_template_update_params.RuleTemplateUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RuleTemplate, + ) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleTemplateList: + """Get rule templates list""" + return await self._get( + "/cdn/resources/rule_templates", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RuleTemplateList, + ) + + async def delete( + self, + rule_template_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete rule template + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cdn/resources/rule_templates/{rule_template_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + rule_template_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleTemplate: + """ + Get rule template details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cdn/resources/rule_templates/{rule_template_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RuleTemplate, + ) + + async def replace( + self, + rule_template_id: int, + *, + rule: str, + rule_type: int, + name: str | Omit = omit, + options: rule_template_replace_params.Options | Omit = omit, + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RuleTemplate: + """ + Change rule template + + Args: + rule: Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + + rule_type: Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + + name: Rule template name. + + options: List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + + override_origin_protocol: Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + + weight: Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/cdn/resources/rule_templates/{rule_template_id}", + body=await async_maybe_transform( + { + "rule": rule, + "rule_type": rule_type, + "name": name, + "options": options, + "override_origin_protocol": override_origin_protocol, + "weight": weight, + }, + rule_template_replace_params.RuleTemplateReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RuleTemplate, + ) + + +class RuleTemplatesResourceWithRawResponse: + def __init__(self, rule_templates: RuleTemplatesResource) -> None: + self._rule_templates = rule_templates + + self.create = to_raw_response_wrapper( + rule_templates.create, + ) + self.update = to_raw_response_wrapper( + rule_templates.update, + ) + self.list = to_raw_response_wrapper( + rule_templates.list, + ) + self.delete = to_raw_response_wrapper( + rule_templates.delete, + ) + self.get = to_raw_response_wrapper( + rule_templates.get, + ) + self.replace = to_raw_response_wrapper( + rule_templates.replace, + ) + + +class AsyncRuleTemplatesResourceWithRawResponse: + def __init__(self, rule_templates: AsyncRuleTemplatesResource) -> None: + self._rule_templates = rule_templates + + self.create = async_to_raw_response_wrapper( + rule_templates.create, + ) + self.update = async_to_raw_response_wrapper( + rule_templates.update, + ) + self.list = async_to_raw_response_wrapper( + rule_templates.list, + ) + self.delete = async_to_raw_response_wrapper( + rule_templates.delete, + ) + self.get = async_to_raw_response_wrapper( + rule_templates.get, + ) + self.replace = async_to_raw_response_wrapper( + rule_templates.replace, + ) + + +class RuleTemplatesResourceWithStreamingResponse: + def __init__(self, rule_templates: RuleTemplatesResource) -> None: + self._rule_templates = rule_templates + + self.create = to_streamed_response_wrapper( + rule_templates.create, + ) + self.update = to_streamed_response_wrapper( + rule_templates.update, + ) + self.list = to_streamed_response_wrapper( + rule_templates.list, + ) + self.delete = to_streamed_response_wrapper( + rule_templates.delete, + ) + self.get = to_streamed_response_wrapper( + rule_templates.get, + ) + self.replace = to_streamed_response_wrapper( + rule_templates.replace, + ) + + +class AsyncRuleTemplatesResourceWithStreamingResponse: + def __init__(self, rule_templates: AsyncRuleTemplatesResource) -> None: + self._rule_templates = rule_templates + + self.create = async_to_streamed_response_wrapper( + rule_templates.create, + ) + self.update = async_to_streamed_response_wrapper( + rule_templates.update, + ) + self.list = async_to_streamed_response_wrapper( + rule_templates.list, + ) + self.delete = async_to_streamed_response_wrapper( + rule_templates.delete, + ) + self.get = async_to_streamed_response_wrapper( + rule_templates.get, + ) + self.replace = async_to_streamed_response_wrapper( + rule_templates.replace, + ) diff --git a/src/gcore/resources/cdn/shields.py b/src/gcore/resources/cdn/shields.py new file mode 100644 index 00000000..07c64807 --- /dev/null +++ b/src/gcore/resources/cdn/shields.py @@ -0,0 +1,135 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.cdn.shield_list_response import ShieldListResponse + +__all__ = ["ShieldsResource", "AsyncShieldsResource"] + + +class ShieldsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ShieldsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ShieldsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ShieldsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ShieldsResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ShieldListResponse: + """Get information about all origin shielding locations available in the account.""" + return self._get( + "/cdn/shieldingpop_v2", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ShieldListResponse, + ) + + +class AsyncShieldsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncShieldsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncShieldsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncShieldsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncShieldsResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ShieldListResponse: + """Get information about all origin shielding locations available in the account.""" + return await self._get( + "/cdn/shieldingpop_v2", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ShieldListResponse, + ) + + +class ShieldsResourceWithRawResponse: + def __init__(self, shields: ShieldsResource) -> None: + self._shields = shields + + self.list = to_raw_response_wrapper( + shields.list, + ) + + +class AsyncShieldsResourceWithRawResponse: + def __init__(self, shields: AsyncShieldsResource) -> None: + self._shields = shields + + self.list = async_to_raw_response_wrapper( + shields.list, + ) + + +class ShieldsResourceWithStreamingResponse: + def __init__(self, shields: ShieldsResource) -> None: + self._shields = shields + + self.list = to_streamed_response_wrapper( + shields.list, + ) + + +class AsyncShieldsResourceWithStreamingResponse: + def __init__(self, shields: AsyncShieldsResource) -> None: + self._shields = shields + + self.list = async_to_streamed_response_wrapper( + shields.list, + ) diff --git a/src/gcore/resources/cdn/statistics.py b/src/gcore/resources/cdn/statistics.py new file mode 100644 index 00000000..0e6a32a6 --- /dev/null +++ b/src/gcore/resources/cdn/statistics.py @@ -0,0 +1,1382 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cdn import ( + statistic_get_logs_usage_series_params, + statistic_get_shield_usage_series_params, + statistic_get_logs_usage_aggregated_params, + statistic_get_resource_usage_series_params, + statistic_get_shield_usage_aggregated_params, + statistic_get_resource_usage_aggregated_params, +) +from ..._base_client import make_request_options +from ...types.cdn.usage_series_stats import UsageSeriesStats +from ...types.cdn.resource_usage_stats import ResourceUsageStats +from ...types.cdn.logs_aggregated_stats import LogsAggregatedStats +from ...types.cdn.shield_aggregated_stats import ShieldAggregatedStats +from ...types.cdn.resource_aggregated_stats import ResourceAggregatedStats + +__all__ = ["StatisticsResource", "AsyncStatisticsResource"] + + +class StatisticsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> StatisticsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return StatisticsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> StatisticsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return StatisticsResourceWithStreamingResponse(self) + + def get_logs_usage_aggregated( + self, + *, + from_: str, + to: str, + flat: bool | Omit = omit, + group_by: str | Omit = omit, + resource: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsAggregatedStats: + """ + Get the number of CDN resources that used Logs uploader. + + Request URL parameters should be added as a query string after the endpoint. + + Args: + from_: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + to: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + flat: The way the parameters are arranged in the response. + + Possible values: + + - **true** – Flat structure is used. + - **false** – Embedded structure is used (default.) + + group_by: Output data grouping. + + Possible value: + + - **resource** - Data is grouped by CDN resources. + + resource: CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/statistics/raw_logs_usage/aggregated", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "to": to, + "flat": flat, + "group_by": group_by, + "resource": resource, + }, + statistic_get_logs_usage_aggregated_params.StatisticGetLogsUsageAggregatedParams, + ), + ), + cast_to=LogsAggregatedStats, + ) + + def get_logs_usage_series( + self, + *, + from_: str, + to: str, + resource: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageSeriesStats: + """ + Get Logs uploader usage statistics for up to 90 days starting today. + + Request URL parameters should be added as a query string after the endpoint. + + Args: + from_: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + to: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + resource: CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/statistics/raw_logs_usage/series", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "to": to, + "resource": resource, + }, + statistic_get_logs_usage_series_params.StatisticGetLogsUsageSeriesParams, + ), + ), + cast_to=UsageSeriesStats, + ) + + def get_resource_usage_aggregated( + self, + *, + from_: str, + metrics: str, + service: str, + to: str, + countries: str | Omit = omit, + flat: bool | Omit = omit, + group_by: str | Omit = omit, + regions: str | Omit = omit, + resource: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ResourceAggregatedStats: + """ + Get aggregated CDN resources statistics. + + Request URL parameters should be added as a query string after the endpoint. + + Aggregated data does not include data for the last two hours. + + Args: + from_: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + metrics: Types of statistics data. + + Possible values: + + - **`upstream_bytes`** – Traffic in bytes from an origin server to CDN servers + or to origin shielding when used. + - **`sent_bytes`** – Traffic in bytes from CDN servers to clients. + - **`shield_bytes`** – Traffic in bytes from origin shielding to CDN servers. + - **`backblaze_bytes`** - Traffic in bytes from Backblaze origin. + - **`total_bytes`** – `shield_bytes`, `upstream_bytes` and `sent_bytes` + combined. + - **`cdn_bytes`** – `sent_bytes` and `shield_bytes` combined. + - **requests** – Number of requests to edge servers. + - **`responses_2xx`** – Number of 2xx response codes. + - **`responses_3xx`** – Number of 3xx response codes. + - **`responses_4xx`** – Number of 4xx response codes. + - **`responses_5xx`** – Number of 5xx response codes. + - **`responses_hit`** – Number of responses with the header Cache: HIT. + - **`responses_miss`** – Number of responses with the header Cache: MISS. + - **`response_types`** – Statistics by content type. It returns a number of + responses for content with different MIME types. + - **`cache_hit_traffic_ratio`** – Formula: 1 - `upstream_bytes` / `sent_bytes`. + We deduct the non-cached traffic from the total traffic amount. + - **`cache_hit_requests_ratio`** – Formula: `responses_hit` / requests. The + share of sending cached content. + - **`shield_traffic_ratio`** – Formula: (`shield_bytes` - `upstream_bytes`) / + `shield_bytes`. The efficiency of the Origin Shielding: how much more traffic + is sent from the Origin Shielding than from the origin. + - **`image_processed`** - Number of images transformed on the Image optimization + service. + - **`request_time`** - Time elapsed between the first bytes of a request were + processed and logging after the last bytes were sent to a user. + - **`upstream_response_time`** - Number of milliseconds it took to receive a + response from an origin. If upstream `response_time_` contains several + indications for one request (in case of more than 1 origin), we summarize + them. In case of aggregating several queries, the average of this amount is + calculated. + - **`95_percentile`** - Represents the 95th percentile of network bandwidth + usage in bytes per second. This means that 95% of the time, the network + resource usage was below this value. + - **`max_bandwidth`** - The maximum network bandwidth that was used during the + selected time represented in bytes per second. + - **`min_bandwidth`** - The minimum network bandwidth that was used during the + selected time represented in bytes per second. + + Metrics **`upstream_response_time`** and **`request_time`** should be requested + separately from other metrics + + service: Service name. + + Possible value: + + - CDN + + to: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + countries: Names of countries for which data should be displayed. English short name from + [ISO 3166 standard][1] without the definite article ("the") should be used. + + [1]: https://www.iso.org/obp/ui/#search/code/ + + To request multiple values, use: + + - &countries=france&countries=denmark + + flat: The way the parameters are arranged in the response. + + Possible values: + + - **true** – Flat structure is used. + - **false** – Embedded structure is used (default.) + + group_by: Output data grouping. + + Possible values: + + - **resource** – Data is grouped by CDN resources IDs. + - **region** – Data is grouped by regions of CDN edge servers. + - **country** – Data is grouped by countries of CDN edge servers. + - **vhost** – Data is grouped by resources CNAMEs. + - **`client_country`** - Data is grouped by countries, based on end-users' + location. + + To request multiple values, use: + + - &`group_by`=region&`group_by`=resource + + regions: Regions for which data is displayed. + + Possible values: + + - **na** – North America + - **eu** – Europe + - **cis** – Commonwealth of Independent States + - **asia** – Asia + - **au** – Australia + - **latam** – Latin America + - **me** – Middle East + - **africa** - Africa + - **sa** - South America + + resource: CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/statistics/aggregate/stats", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "metrics": metrics, + "service": service, + "to": to, + "countries": countries, + "flat": flat, + "group_by": group_by, + "regions": regions, + "resource": resource, + }, + statistic_get_resource_usage_aggregated_params.StatisticGetResourceUsageAggregatedParams, + ), + ), + cast_to=ResourceAggregatedStats, + ) + + def get_resource_usage_series( + self, + *, + from_: str, + granularity: str, + metrics: str, + service: str, + to: str, + countries: str | Omit = omit, + group_by: str | Omit = omit, + regions: str | Omit = omit, + resource: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ResourceUsageStats: + """ + Get CDN resources statistics for up to 365 days starting today. + + Args: + from_: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + granularity: Duration of the time blocks into which the data will be divided. + + Possible values: + + - **1m** - available only for up to 1 month in the past. + - **5m** + - **15m** + - **1h** + - **1d** + + metrics: Types of statistics data. + + Possible values: + + - **`upstream_bytes`** – Traffic in bytes from an origin server to CDN servers + or to origin shielding when used. + - **`sent_bytes`** – Traffic in bytes from CDN servers to clients. + - **`shield_bytes`** – Traffic in bytes from origin shielding to CDN servers. + - **`backblaze_bytes`** - Traffic in bytes from Backblaze origin. + - **`total_bytes`** – `shield_bytes`, `upstream_bytes` and `sent_bytes` + combined. + - **`cdn_bytes`** – `sent_bytes` and `shield_bytes` combined. + - **requests** – Number of requests to edge servers. + - **`responses_2xx`** – Number of 2xx response codes. + - **`responses_3xx`** – Number of 3xx response codes. + - **`responses_4xx`** – Number of 4xx response codes. + - **`responses_5xx`** – Number of 5xx response codes. + - **`responses_hit`** – Number of responses with the header Cache: HIT. + - **`responses_miss`** – Number of responses with the header Cache: MISS. + - **`response_types`** – Statistics by content type. It returns a number of + responses for content with different MIME types. + - **`cache_hit_traffic_ratio`** – Formula: 1 - `upstream_bytes` / `sent_bytes`. + We deduct the non-cached traffic from the total traffic amount. + - **`cache_hit_requests_ratio`** – Formula: `responses_hit` / requests. The + share of sending cached content. + - **`shield_traffic_ratio`** – Formula: (`shield_bytes` - `upstream_bytes`) / + `shield_bytes`. The efficiency of the Origin Shielding: how much more traffic + is sent from the Origin Shielding than from the origin. + - **`image_processed`** - Number of images transformed on the Image optimization + service. + - **`request_time`** - Time elapsed between the first bytes of a request were + processed and logging after the last bytes were sent to a user. + - **`upstream_response_time`** - Number of milliseconds it took to receive a + response from an origin. If upstream `response_time_` contains several + indications for one request (in case of more than 1 origin), we summarize + them. In case of aggregating several queries, the average of this amount is + calculated. + + Metrics **`upstream_response_time`** and **`request_time`** should be requested + separately from other metrics + + service: Service name. + + Possible value: + + - CDN + + to: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + countries: Names of countries for which data should be displayed. English short name from + [ISO 3166 standard][1] without the definite article ("the") should be used. + + [1]: https://www.iso.org/obp/ui/#search/code/ + + To request multiple values, use: + + - &countries=france&countries=denmark + + group_by: Output data grouping. + + Possible values: + + - **resource** – Data is grouped by CDN resources IDs. + - **region** – Data is grouped by regions of CDN edge servers. + - **country** – Data is grouped by countries of CDN edge servers. + - **vhost** – Data is grouped by resources CNAMEs. + - **`client_country`** - Data is grouped by countries, based on end-users' + location. + + To request multiple values, use: + + - &`group_by`=region&`group_by`=resource + + regions: Regions for which data is displayed. + + Possible values: + + - **na** – North America + - **eu** – Europe + - **cis** – Commonwealth of Independent States + - **asia** – Asia + - **au** – Australia + - **latam** – Latin America + - **me** – Middle East + - **africa** - Africa + - **sa** - South America + + resource: CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/statistics/series", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "granularity": granularity, + "metrics": metrics, + "service": service, + "to": to, + "countries": countries, + "group_by": group_by, + "regions": regions, + "resource": resource, + }, + statistic_get_resource_usage_series_params.StatisticGetResourceUsageSeriesParams, + ), + ), + cast_to=ResourceUsageStats, + ) + + def get_shield_usage_aggregated( + self, + *, + from_: str, + to: str, + flat: bool | Omit = omit, + group_by: str | Omit = omit, + resource: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ShieldAggregatedStats: + """ + The number of CDN resources that use origin shielding. + + Request URL parameters should be added as a query string after the endpoint. + + Args: + from_: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + to: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + flat: The way the parameters are arranged in the response. + + Possible values: + + - **true** – Flat structure is used. + - **false** – Embedded structure is used (default.) + + group_by: Output data grouping. + + Possible value: + + - **resource** - Data is grouped by CDN resources. + + resource: CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/statistics/shield_usage/aggregated", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "to": to, + "flat": flat, + "group_by": group_by, + "resource": resource, + }, + statistic_get_shield_usage_aggregated_params.StatisticGetShieldUsageAggregatedParams, + ), + ), + cast_to=ShieldAggregatedStats, + ) + + def get_shield_usage_series( + self, + *, + from_: str, + to: str, + resource: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageSeriesStats: + """ + Get origin shielding usage statistics for up to 365 days starting from today. + + Request URL parameters should be added as a query string after the endpoint. + + Args: + from_: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + to: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + resource: CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/statistics/shield_usage/series", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "to": to, + "resource": resource, + }, + statistic_get_shield_usage_series_params.StatisticGetShieldUsageSeriesParams, + ), + ), + cast_to=UsageSeriesStats, + ) + + +class AsyncStatisticsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncStatisticsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncStatisticsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncStatisticsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncStatisticsResourceWithStreamingResponse(self) + + async def get_logs_usage_aggregated( + self, + *, + from_: str, + to: str, + flat: bool | Omit = omit, + group_by: str | Omit = omit, + resource: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LogsAggregatedStats: + """ + Get the number of CDN resources that used Logs uploader. + + Request URL parameters should be added as a query string after the endpoint. + + Args: + from_: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + to: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + flat: The way the parameters are arranged in the response. + + Possible values: + + - **true** – Flat structure is used. + - **false** – Embedded structure is used (default.) + + group_by: Output data grouping. + + Possible value: + + - **resource** - Data is grouped by CDN resources. + + resource: CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/statistics/raw_logs_usage/aggregated", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "to": to, + "flat": flat, + "group_by": group_by, + "resource": resource, + }, + statistic_get_logs_usage_aggregated_params.StatisticGetLogsUsageAggregatedParams, + ), + ), + cast_to=LogsAggregatedStats, + ) + + async def get_logs_usage_series( + self, + *, + from_: str, + to: str, + resource: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageSeriesStats: + """ + Get Logs uploader usage statistics for up to 90 days starting today. + + Request URL parameters should be added as a query string after the endpoint. + + Args: + from_: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + to: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + resource: CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/statistics/raw_logs_usage/series", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "to": to, + "resource": resource, + }, + statistic_get_logs_usage_series_params.StatisticGetLogsUsageSeriesParams, + ), + ), + cast_to=UsageSeriesStats, + ) + + async def get_resource_usage_aggregated( + self, + *, + from_: str, + metrics: str, + service: str, + to: str, + countries: str | Omit = omit, + flat: bool | Omit = omit, + group_by: str | Omit = omit, + regions: str | Omit = omit, + resource: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ResourceAggregatedStats: + """ + Get aggregated CDN resources statistics. + + Request URL parameters should be added as a query string after the endpoint. + + Aggregated data does not include data for the last two hours. + + Args: + from_: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + metrics: Types of statistics data. + + Possible values: + + - **`upstream_bytes`** – Traffic in bytes from an origin server to CDN servers + or to origin shielding when used. + - **`sent_bytes`** – Traffic in bytes from CDN servers to clients. + - **`shield_bytes`** – Traffic in bytes from origin shielding to CDN servers. + - **`backblaze_bytes`** - Traffic in bytes from Backblaze origin. + - **`total_bytes`** – `shield_bytes`, `upstream_bytes` and `sent_bytes` + combined. + - **`cdn_bytes`** – `sent_bytes` and `shield_bytes` combined. + - **requests** – Number of requests to edge servers. + - **`responses_2xx`** – Number of 2xx response codes. + - **`responses_3xx`** – Number of 3xx response codes. + - **`responses_4xx`** – Number of 4xx response codes. + - **`responses_5xx`** – Number of 5xx response codes. + - **`responses_hit`** – Number of responses with the header Cache: HIT. + - **`responses_miss`** – Number of responses with the header Cache: MISS. + - **`response_types`** – Statistics by content type. It returns a number of + responses for content with different MIME types. + - **`cache_hit_traffic_ratio`** – Formula: 1 - `upstream_bytes` / `sent_bytes`. + We deduct the non-cached traffic from the total traffic amount. + - **`cache_hit_requests_ratio`** – Formula: `responses_hit` / requests. The + share of sending cached content. + - **`shield_traffic_ratio`** – Formula: (`shield_bytes` - `upstream_bytes`) / + `shield_bytes`. The efficiency of the Origin Shielding: how much more traffic + is sent from the Origin Shielding than from the origin. + - **`image_processed`** - Number of images transformed on the Image optimization + service. + - **`request_time`** - Time elapsed between the first bytes of a request were + processed and logging after the last bytes were sent to a user. + - **`upstream_response_time`** - Number of milliseconds it took to receive a + response from an origin. If upstream `response_time_` contains several + indications for one request (in case of more than 1 origin), we summarize + them. In case of aggregating several queries, the average of this amount is + calculated. + - **`95_percentile`** - Represents the 95th percentile of network bandwidth + usage in bytes per second. This means that 95% of the time, the network + resource usage was below this value. + - **`max_bandwidth`** - The maximum network bandwidth that was used during the + selected time represented in bytes per second. + - **`min_bandwidth`** - The minimum network bandwidth that was used during the + selected time represented in bytes per second. + + Metrics **`upstream_response_time`** and **`request_time`** should be requested + separately from other metrics + + service: Service name. + + Possible value: + + - CDN + + to: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + countries: Names of countries for which data should be displayed. English short name from + [ISO 3166 standard][1] without the definite article ("the") should be used. + + [1]: https://www.iso.org/obp/ui/#search/code/ + + To request multiple values, use: + + - &countries=france&countries=denmark + + flat: The way the parameters are arranged in the response. + + Possible values: + + - **true** – Flat structure is used. + - **false** – Embedded structure is used (default.) + + group_by: Output data grouping. + + Possible values: + + - **resource** – Data is grouped by CDN resources IDs. + - **region** – Data is grouped by regions of CDN edge servers. + - **country** – Data is grouped by countries of CDN edge servers. + - **vhost** – Data is grouped by resources CNAMEs. + - **`client_country`** - Data is grouped by countries, based on end-users' + location. + + To request multiple values, use: + + - &`group_by`=region&`group_by`=resource + + regions: Regions for which data is displayed. + + Possible values: + + - **na** – North America + - **eu** – Europe + - **cis** – Commonwealth of Independent States + - **asia** – Asia + - **au** – Australia + - **latam** – Latin America + - **me** – Middle East + - **africa** - Africa + - **sa** - South America + + resource: CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/statistics/aggregate/stats", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "metrics": metrics, + "service": service, + "to": to, + "countries": countries, + "flat": flat, + "group_by": group_by, + "regions": regions, + "resource": resource, + }, + statistic_get_resource_usage_aggregated_params.StatisticGetResourceUsageAggregatedParams, + ), + ), + cast_to=ResourceAggregatedStats, + ) + + async def get_resource_usage_series( + self, + *, + from_: str, + granularity: str, + metrics: str, + service: str, + to: str, + countries: str | Omit = omit, + group_by: str | Omit = omit, + regions: str | Omit = omit, + resource: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ResourceUsageStats: + """ + Get CDN resources statistics for up to 365 days starting today. + + Args: + from_: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + granularity: Duration of the time blocks into which the data will be divided. + + Possible values: + + - **1m** - available only for up to 1 month in the past. + - **5m** + - **15m** + - **1h** + - **1d** + + metrics: Types of statistics data. + + Possible values: + + - **`upstream_bytes`** – Traffic in bytes from an origin server to CDN servers + or to origin shielding when used. + - **`sent_bytes`** – Traffic in bytes from CDN servers to clients. + - **`shield_bytes`** – Traffic in bytes from origin shielding to CDN servers. + - **`backblaze_bytes`** - Traffic in bytes from Backblaze origin. + - **`total_bytes`** – `shield_bytes`, `upstream_bytes` and `sent_bytes` + combined. + - **`cdn_bytes`** – `sent_bytes` and `shield_bytes` combined. + - **requests** – Number of requests to edge servers. + - **`responses_2xx`** – Number of 2xx response codes. + - **`responses_3xx`** – Number of 3xx response codes. + - **`responses_4xx`** – Number of 4xx response codes. + - **`responses_5xx`** – Number of 5xx response codes. + - **`responses_hit`** – Number of responses with the header Cache: HIT. + - **`responses_miss`** – Number of responses with the header Cache: MISS. + - **`response_types`** – Statistics by content type. It returns a number of + responses for content with different MIME types. + - **`cache_hit_traffic_ratio`** – Formula: 1 - `upstream_bytes` / `sent_bytes`. + We deduct the non-cached traffic from the total traffic amount. + - **`cache_hit_requests_ratio`** – Formula: `responses_hit` / requests. The + share of sending cached content. + - **`shield_traffic_ratio`** – Formula: (`shield_bytes` - `upstream_bytes`) / + `shield_bytes`. The efficiency of the Origin Shielding: how much more traffic + is sent from the Origin Shielding than from the origin. + - **`image_processed`** - Number of images transformed on the Image optimization + service. + - **`request_time`** - Time elapsed between the first bytes of a request were + processed and logging after the last bytes were sent to a user. + - **`upstream_response_time`** - Number of milliseconds it took to receive a + response from an origin. If upstream `response_time_` contains several + indications for one request (in case of more than 1 origin), we summarize + them. In case of aggregating several queries, the average of this amount is + calculated. + + Metrics **`upstream_response_time`** and **`request_time`** should be requested + separately from other metrics + + service: Service name. + + Possible value: + + - CDN + + to: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + countries: Names of countries for which data should be displayed. English short name from + [ISO 3166 standard][1] without the definite article ("the") should be used. + + [1]: https://www.iso.org/obp/ui/#search/code/ + + To request multiple values, use: + + - &countries=france&countries=denmark + + group_by: Output data grouping. + + Possible values: + + - **resource** – Data is grouped by CDN resources IDs. + - **region** – Data is grouped by regions of CDN edge servers. + - **country** – Data is grouped by countries of CDN edge servers. + - **vhost** – Data is grouped by resources CNAMEs. + - **`client_country`** - Data is grouped by countries, based on end-users' + location. + + To request multiple values, use: + + - &`group_by`=region&`group_by`=resource + + regions: Regions for which data is displayed. + + Possible values: + + - **na** – North America + - **eu** – Europe + - **cis** – Commonwealth of Independent States + - **asia** – Asia + - **au** – Australia + - **latam** – Latin America + - **me** – Middle East + - **africa** - Africa + - **sa** - South America + + resource: CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/statistics/series", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "granularity": granularity, + "metrics": metrics, + "service": service, + "to": to, + "countries": countries, + "group_by": group_by, + "regions": regions, + "resource": resource, + }, + statistic_get_resource_usage_series_params.StatisticGetResourceUsageSeriesParams, + ), + ), + cast_to=ResourceUsageStats, + ) + + async def get_shield_usage_aggregated( + self, + *, + from_: str, + to: str, + flat: bool | Omit = omit, + group_by: str | Omit = omit, + resource: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ShieldAggregatedStats: + """ + The number of CDN resources that use origin shielding. + + Request URL parameters should be added as a query string after the endpoint. + + Args: + from_: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + to: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + flat: The way the parameters are arranged in the response. + + Possible values: + + - **true** – Flat structure is used. + - **false** – Embedded structure is used (default.) + + group_by: Output data grouping. + + Possible value: + + - **resource** - Data is grouped by CDN resources. + + resource: CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/statistics/shield_usage/aggregated", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "to": to, + "flat": flat, + "group_by": group_by, + "resource": resource, + }, + statistic_get_shield_usage_aggregated_params.StatisticGetShieldUsageAggregatedParams, + ), + ), + cast_to=ShieldAggregatedStats, + ) + + async def get_shield_usage_series( + self, + *, + from_: str, + to: str, + resource: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageSeriesStats: + """ + Get origin shielding usage statistics for up to 365 days starting from today. + + Request URL parameters should be added as a query string after the endpoint. + + Args: + from_: Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + to: End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + resource: CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/statistics/shield_usage/series", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "to": to, + "resource": resource, + }, + statistic_get_shield_usage_series_params.StatisticGetShieldUsageSeriesParams, + ), + ), + cast_to=UsageSeriesStats, + ) + + +class StatisticsResourceWithRawResponse: + def __init__(self, statistics: StatisticsResource) -> None: + self._statistics = statistics + + self.get_logs_usage_aggregated = to_raw_response_wrapper( + statistics.get_logs_usage_aggregated, + ) + self.get_logs_usage_series = to_raw_response_wrapper( + statistics.get_logs_usage_series, + ) + self.get_resource_usage_aggregated = to_raw_response_wrapper( + statistics.get_resource_usage_aggregated, + ) + self.get_resource_usage_series = to_raw_response_wrapper( + statistics.get_resource_usage_series, + ) + self.get_shield_usage_aggregated = to_raw_response_wrapper( + statistics.get_shield_usage_aggregated, + ) + self.get_shield_usage_series = to_raw_response_wrapper( + statistics.get_shield_usage_series, + ) + + +class AsyncStatisticsResourceWithRawResponse: + def __init__(self, statistics: AsyncStatisticsResource) -> None: + self._statistics = statistics + + self.get_logs_usage_aggregated = async_to_raw_response_wrapper( + statistics.get_logs_usage_aggregated, + ) + self.get_logs_usage_series = async_to_raw_response_wrapper( + statistics.get_logs_usage_series, + ) + self.get_resource_usage_aggregated = async_to_raw_response_wrapper( + statistics.get_resource_usage_aggregated, + ) + self.get_resource_usage_series = async_to_raw_response_wrapper( + statistics.get_resource_usage_series, + ) + self.get_shield_usage_aggregated = async_to_raw_response_wrapper( + statistics.get_shield_usage_aggregated, + ) + self.get_shield_usage_series = async_to_raw_response_wrapper( + statistics.get_shield_usage_series, + ) + + +class StatisticsResourceWithStreamingResponse: + def __init__(self, statistics: StatisticsResource) -> None: + self._statistics = statistics + + self.get_logs_usage_aggregated = to_streamed_response_wrapper( + statistics.get_logs_usage_aggregated, + ) + self.get_logs_usage_series = to_streamed_response_wrapper( + statistics.get_logs_usage_series, + ) + self.get_resource_usage_aggregated = to_streamed_response_wrapper( + statistics.get_resource_usage_aggregated, + ) + self.get_resource_usage_series = to_streamed_response_wrapper( + statistics.get_resource_usage_series, + ) + self.get_shield_usage_aggregated = to_streamed_response_wrapper( + statistics.get_shield_usage_aggregated, + ) + self.get_shield_usage_series = to_streamed_response_wrapper( + statistics.get_shield_usage_series, + ) + + +class AsyncStatisticsResourceWithStreamingResponse: + def __init__(self, statistics: AsyncStatisticsResource) -> None: + self._statistics = statistics + + self.get_logs_usage_aggregated = async_to_streamed_response_wrapper( + statistics.get_logs_usage_aggregated, + ) + self.get_logs_usage_series = async_to_streamed_response_wrapper( + statistics.get_logs_usage_series, + ) + self.get_resource_usage_aggregated = async_to_streamed_response_wrapper( + statistics.get_resource_usage_aggregated, + ) + self.get_resource_usage_series = async_to_streamed_response_wrapper( + statistics.get_resource_usage_series, + ) + self.get_shield_usage_aggregated = async_to_streamed_response_wrapper( + statistics.get_shield_usage_aggregated, + ) + self.get_shield_usage_series = async_to_streamed_response_wrapper( + statistics.get_shield_usage_series, + ) diff --git a/src/gcore/resources/cdn/trusted_ca_certificates.py b/src/gcore/resources/cdn/trusted_ca_certificates.py new file mode 100644 index 00000000..3ac42d0b --- /dev/null +++ b/src/gcore/resources/cdn/trusted_ca_certificates.py @@ -0,0 +1,572 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cdn import ( + trusted_ca_certificate_list_params, + trusted_ca_certificate_create_params, + trusted_ca_certificate_replace_params, +) +from ..._base_client import make_request_options +from ...types.cdn.ca_certificate import CaCertificate +from ...types.cdn.ca_certificate_list import CaCertificateList + +__all__ = ["TrustedCaCertificatesResource", "AsyncTrustedCaCertificatesResource"] + + +class TrustedCaCertificatesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> TrustedCaCertificatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return TrustedCaCertificatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TrustedCaCertificatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return TrustedCaCertificatesResourceWithStreamingResponse(self) + + def create( + self, + *, + name: str, + ssl_certificate: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CaCertificate: + """ + Add a trusted CA certificate to verify an origin. + + Enter all strings of the certificate in one string parameter. Each string should + be separated by the "\n" symbol. + + Args: + name: CA certificate name. + + It must be unique. + + ssl_certificate: Public part of the CA certificate. + + It must be in the PEM format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/cdn/sslCertificates", + body=maybe_transform( + { + "name": name, + "ssl_certificate": ssl_certificate, + }, + trusted_ca_certificate_create_params.TrustedCaCertificateCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CaCertificate, + ) + + def list( + self, + *, + automated: bool | Omit = omit, + resource_id: int | Omit = omit, + validity_not_after_lte: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CaCertificateList: + """ + Get list of trusted CA certificates used to verify an origin. + + Args: + automated: How the certificate was issued. + + Possible values: + + - **true** – Certificate was issued automatically. + - **false** – Certificate was added by a user. + + resource_id: CDN resource ID for which the certificates are requested. + + validity_not_after_lte: Date and time when the certificate become untrusted (ISO 8601/RFC 3339 format, + UTC.) + + Response will contain certificates valid until the specified time. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cdn/sslCertificates", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "automated": automated, + "resource_id": resource_id, + "validity_not_after_lte": validity_not_after_lte, + }, + trusted_ca_certificate_list_params.TrustedCaCertificateListParams, + ), + ), + cast_to=CaCertificateList, + ) + + def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete trusted CA certificate + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cdn/sslCertificates/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CaCertificate: + """ + Get trusted CA certificate details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cdn/sslCertificates/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CaCertificate, + ) + + def replace( + self, + id: int, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CaCertificate: + """ + Change trusted CA certificate + + Args: + name: CA certificate name. + + It must be unique. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/cdn/sslCertificates/{id}", + body=maybe_transform( + {"name": name}, trusted_ca_certificate_replace_params.TrustedCaCertificateReplaceParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CaCertificate, + ) + + +class AsyncTrustedCaCertificatesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncTrustedCaCertificatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncTrustedCaCertificatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTrustedCaCertificatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncTrustedCaCertificatesResourceWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + ssl_certificate: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CaCertificate: + """ + Add a trusted CA certificate to verify an origin. + + Enter all strings of the certificate in one string parameter. Each string should + be separated by the "\n" symbol. + + Args: + name: CA certificate name. + + It must be unique. + + ssl_certificate: Public part of the CA certificate. + + It must be in the PEM format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/cdn/sslCertificates", + body=await async_maybe_transform( + { + "name": name, + "ssl_certificate": ssl_certificate, + }, + trusted_ca_certificate_create_params.TrustedCaCertificateCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CaCertificate, + ) + + async def list( + self, + *, + automated: bool | Omit = omit, + resource_id: int | Omit = omit, + validity_not_after_lte: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CaCertificateList: + """ + Get list of trusted CA certificates used to verify an origin. + + Args: + automated: How the certificate was issued. + + Possible values: + + - **true** – Certificate was issued automatically. + - **false** – Certificate was added by a user. + + resource_id: CDN resource ID for which the certificates are requested. + + validity_not_after_lte: Date and time when the certificate become untrusted (ISO 8601/RFC 3339 format, + UTC.) + + Response will contain certificates valid until the specified time. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cdn/sslCertificates", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "automated": automated, + "resource_id": resource_id, + "validity_not_after_lte": validity_not_after_lte, + }, + trusted_ca_certificate_list_params.TrustedCaCertificateListParams, + ), + ), + cast_to=CaCertificateList, + ) + + async def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete trusted CA certificate + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cdn/sslCertificates/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CaCertificate: + """ + Get trusted CA certificate details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cdn/sslCertificates/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CaCertificate, + ) + + async def replace( + self, + id: int, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CaCertificate: + """ + Change trusted CA certificate + + Args: + name: CA certificate name. + + It must be unique. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/cdn/sslCertificates/{id}", + body=await async_maybe_transform( + {"name": name}, trusted_ca_certificate_replace_params.TrustedCaCertificateReplaceParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CaCertificate, + ) + + +class TrustedCaCertificatesResourceWithRawResponse: + def __init__(self, trusted_ca_certificates: TrustedCaCertificatesResource) -> None: + self._trusted_ca_certificates = trusted_ca_certificates + + self.create = to_raw_response_wrapper( + trusted_ca_certificates.create, + ) + self.list = to_raw_response_wrapper( + trusted_ca_certificates.list, + ) + self.delete = to_raw_response_wrapper( + trusted_ca_certificates.delete, + ) + self.get = to_raw_response_wrapper( + trusted_ca_certificates.get, + ) + self.replace = to_raw_response_wrapper( + trusted_ca_certificates.replace, + ) + + +class AsyncTrustedCaCertificatesResourceWithRawResponse: + def __init__(self, trusted_ca_certificates: AsyncTrustedCaCertificatesResource) -> None: + self._trusted_ca_certificates = trusted_ca_certificates + + self.create = async_to_raw_response_wrapper( + trusted_ca_certificates.create, + ) + self.list = async_to_raw_response_wrapper( + trusted_ca_certificates.list, + ) + self.delete = async_to_raw_response_wrapper( + trusted_ca_certificates.delete, + ) + self.get = async_to_raw_response_wrapper( + trusted_ca_certificates.get, + ) + self.replace = async_to_raw_response_wrapper( + trusted_ca_certificates.replace, + ) + + +class TrustedCaCertificatesResourceWithStreamingResponse: + def __init__(self, trusted_ca_certificates: TrustedCaCertificatesResource) -> None: + self._trusted_ca_certificates = trusted_ca_certificates + + self.create = to_streamed_response_wrapper( + trusted_ca_certificates.create, + ) + self.list = to_streamed_response_wrapper( + trusted_ca_certificates.list, + ) + self.delete = to_streamed_response_wrapper( + trusted_ca_certificates.delete, + ) + self.get = to_streamed_response_wrapper( + trusted_ca_certificates.get, + ) + self.replace = to_streamed_response_wrapper( + trusted_ca_certificates.replace, + ) + + +class AsyncTrustedCaCertificatesResourceWithStreamingResponse: + def __init__(self, trusted_ca_certificates: AsyncTrustedCaCertificatesResource) -> None: + self._trusted_ca_certificates = trusted_ca_certificates + + self.create = async_to_streamed_response_wrapper( + trusted_ca_certificates.create, + ) + self.list = async_to_streamed_response_wrapper( + trusted_ca_certificates.list, + ) + self.delete = async_to_streamed_response_wrapper( + trusted_ca_certificates.delete, + ) + self.get = async_to_streamed_response_wrapper( + trusted_ca_certificates.get, + ) + self.replace = async_to_streamed_response_wrapper( + trusted_ca_certificates.replace, + ) diff --git a/src/gcore/resources/cloud/__init__.py b/src/gcore/resources/cloud/__init__.py new file mode 100644 index 00000000..df7277aa --- /dev/null +++ b/src/gcore/resources/cloud/__init__.py @@ -0,0 +1,425 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .k8s import ( + K8SResource, + AsyncK8SResource, + K8SResourceWithRawResponse, + AsyncK8SResourceWithRawResponse, + K8SResourceWithStreamingResponse, + AsyncK8SResourceWithStreamingResponse, +) +from .cloud import ( + CloudResource, + AsyncCloudResource, + CloudResourceWithRawResponse, + AsyncCloudResourceWithRawResponse, + CloudResourceWithStreamingResponse, + AsyncCloudResourceWithStreamingResponse, +) +from .tasks import ( + TasksResource, + AsyncTasksResource, + TasksResourceWithRawResponse, + AsyncTasksResourceWithRawResponse, + TasksResourceWithStreamingResponse, + AsyncTasksResourceWithStreamingResponse, +) +from .users import ( + UsersResource, + AsyncUsersResource, + UsersResourceWithRawResponse, + AsyncUsersResourceWithRawResponse, + UsersResourceWithStreamingResponse, + AsyncUsersResourceWithStreamingResponse, +) +from .quotas import ( + QuotasResource, + AsyncQuotasResource, + QuotasResourceWithRawResponse, + AsyncQuotasResourceWithRawResponse, + QuotasResourceWithStreamingResponse, + AsyncQuotasResourceWithStreamingResponse, +) +from .regions import ( + RegionsResource, + AsyncRegionsResource, + RegionsResourceWithRawResponse, + AsyncRegionsResourceWithRawResponse, + RegionsResourceWithStreamingResponse, + AsyncRegionsResourceWithStreamingResponse, +) +from .secrets import ( + SecretsResource, + AsyncSecretsResource, + SecretsResourceWithRawResponse, + AsyncSecretsResourceWithRawResponse, + SecretsResourceWithStreamingResponse, + AsyncSecretsResourceWithStreamingResponse, +) +from .volumes import ( + VolumesResource, + AsyncVolumesResource, + VolumesResourceWithRawResponse, + AsyncVolumesResourceWithRawResponse, + VolumesResourceWithStreamingResponse, + AsyncVolumesResourceWithStreamingResponse, +) +from .networks import ( + NetworksResource, + AsyncNetworksResource, + NetworksResourceWithRawResponse, + AsyncNetworksResourceWithRawResponse, + NetworksResourceWithStreamingResponse, + AsyncNetworksResourceWithStreamingResponse, +) +from .projects import ( + ProjectsResource, + AsyncProjectsResource, + ProjectsResourceWithRawResponse, + AsyncProjectsResourceWithRawResponse, + ProjectsResourceWithStreamingResponse, + AsyncProjectsResourceWithStreamingResponse, +) +from .ssh_keys import ( + SSHKeysResource, + AsyncSSHKeysResource, + SSHKeysResourceWithRawResponse, + AsyncSSHKeysResourceWithRawResponse, + SSHKeysResourceWithStreamingResponse, + AsyncSSHKeysResourceWithStreamingResponse, +) +from .baremetal import ( + BaremetalResource, + AsyncBaremetalResource, + BaremetalResourceWithRawResponse, + AsyncBaremetalResourceWithRawResponse, + BaremetalResourceWithStreamingResponse, + AsyncBaremetalResourceWithStreamingResponse, +) +from .databases import ( + DatabasesResource, + AsyncDatabasesResource, + DatabasesResourceWithRawResponse, + AsyncDatabasesResourceWithRawResponse, + DatabasesResourceWithStreamingResponse, + AsyncDatabasesResourceWithStreamingResponse, +) +from .inference import ( + InferenceResource, + AsyncInferenceResource, + InferenceResourceWithRawResponse, + AsyncInferenceResourceWithRawResponse, + InferenceResourceWithStreamingResponse, + AsyncInferenceResourceWithStreamingResponse, +) +from .instances import ( + InstancesResource, + AsyncInstancesResource, + InstancesResourceWithRawResponse, + AsyncInstancesResourceWithRawResponse, + InstancesResourceWithStreamingResponse, + AsyncInstancesResourceWithStreamingResponse, +) +from .ip_ranges import ( + IPRangesResource, + AsyncIPRangesResource, + IPRangesResourceWithRawResponse, + AsyncIPRangesResourceWithRawResponse, + IPRangesResourceWithStreamingResponse, + AsyncIPRangesResourceWithStreamingResponse, +) +from .audit_logs import ( + AuditLogsResource, + AsyncAuditLogsResource, + AuditLogsResourceWithRawResponse, + AsyncAuditLogsResourceWithRawResponse, + AuditLogsResourceWithStreamingResponse, + AsyncAuditLogsResourceWithStreamingResponse, +) +from .registries import ( + RegistriesResource, + AsyncRegistriesResource, + RegistriesResourceWithRawResponse, + AsyncRegistriesResourceWithRawResponse, + RegistriesResourceWithStreamingResponse, + AsyncRegistriesResourceWithStreamingResponse, +) +from .file_shares import ( + FileSharesResource, + AsyncFileSharesResource, + FileSharesResourceWithRawResponse, + AsyncFileSharesResourceWithRawResponse, + FileSharesResourceWithStreamingResponse, + AsyncFileSharesResourceWithStreamingResponse, +) +from .gpu_virtual import ( + GPUVirtualResource, + AsyncGPUVirtualResource, + GPUVirtualResourceWithRawResponse, + AsyncGPUVirtualResourceWithRawResponse, + GPUVirtualResourceWithStreamingResponse, + AsyncGPUVirtualResourceWithStreamingResponse, +) +from .cost_reports import ( + CostReportsResource, + AsyncCostReportsResource, + CostReportsResourceWithRawResponse, + AsyncCostReportsResourceWithRawResponse, + CostReportsResourceWithStreamingResponse, + AsyncCostReportsResourceWithStreamingResponse, +) +from .floating_ips import ( + FloatingIPsResource, + AsyncFloatingIPsResource, + FloatingIPsResourceWithRawResponse, + AsyncFloatingIPsResourceWithRawResponse, + FloatingIPsResourceWithStreamingResponse, + AsyncFloatingIPsResourceWithStreamingResponse, +) +from .gpu_baremetal import ( + GPUBaremetalResource, + AsyncGPUBaremetalResource, + GPUBaremetalResourceWithRawResponse, + AsyncGPUBaremetalResourceWithRawResponse, + GPUBaremetalResourceWithStreamingResponse, + AsyncGPUBaremetalResourceWithStreamingResponse, +) +from .usage_reports import ( + UsageReportsResource, + AsyncUsageReportsResource, + UsageReportsResourceWithRawResponse, + AsyncUsageReportsResourceWithRawResponse, + UsageReportsResourceWithStreamingResponse, + AsyncUsageReportsResourceWithStreamingResponse, +) +from .load_balancers import ( + LoadBalancersResource, + AsyncLoadBalancersResource, + LoadBalancersResourceWithRawResponse, + AsyncLoadBalancersResourceWithRawResponse, + LoadBalancersResourceWithStreamingResponse, + AsyncLoadBalancersResourceWithStreamingResponse, +) +from .security_groups import ( + SecurityGroupsResource, + AsyncSecurityGroupsResource, + SecurityGroupsResourceWithRawResponse, + AsyncSecurityGroupsResourceWithRawResponse, + SecurityGroupsResourceWithStreamingResponse, + AsyncSecurityGroupsResourceWithStreamingResponse, +) +from .placement_groups import ( + PlacementGroupsResource, + AsyncPlacementGroupsResource, + PlacementGroupsResourceWithRawResponse, + AsyncPlacementGroupsResourceWithRawResponse, + PlacementGroupsResourceWithStreamingResponse, + AsyncPlacementGroupsResourceWithStreamingResponse, +) +from .volume_snapshots import ( + VolumeSnapshotsResource, + AsyncVolumeSnapshotsResource, + VolumeSnapshotsResourceWithRawResponse, + AsyncVolumeSnapshotsResourceWithRawResponse, + VolumeSnapshotsResourceWithStreamingResponse, + AsyncVolumeSnapshotsResourceWithStreamingResponse, +) +from .reserved_fixed_ips import ( + ReservedFixedIPsResource, + AsyncReservedFixedIPsResource, + ReservedFixedIPsResourceWithRawResponse, + AsyncReservedFixedIPsResourceWithRawResponse, + ReservedFixedIPsResourceWithStreamingResponse, + AsyncReservedFixedIPsResourceWithStreamingResponse, +) +from .billing_reservations import ( + BillingReservationsResource, + AsyncBillingReservationsResource, + BillingReservationsResourceWithRawResponse, + AsyncBillingReservationsResourceWithRawResponse, + BillingReservationsResourceWithStreamingResponse, + AsyncBillingReservationsResourceWithStreamingResponse, +) + +__all__ = [ + "ProjectsResource", + "AsyncProjectsResource", + "ProjectsResourceWithRawResponse", + "AsyncProjectsResourceWithRawResponse", + "ProjectsResourceWithStreamingResponse", + "AsyncProjectsResourceWithStreamingResponse", + "TasksResource", + "AsyncTasksResource", + "TasksResourceWithRawResponse", + "AsyncTasksResourceWithRawResponse", + "TasksResourceWithStreamingResponse", + "AsyncTasksResourceWithStreamingResponse", + "RegionsResource", + "AsyncRegionsResource", + "RegionsResourceWithRawResponse", + "AsyncRegionsResourceWithRawResponse", + "RegionsResourceWithStreamingResponse", + "AsyncRegionsResourceWithStreamingResponse", + "QuotasResource", + "AsyncQuotasResource", + "QuotasResourceWithRawResponse", + "AsyncQuotasResourceWithRawResponse", + "QuotasResourceWithStreamingResponse", + "AsyncQuotasResourceWithStreamingResponse", + "SecretsResource", + "AsyncSecretsResource", + "SecretsResourceWithRawResponse", + "AsyncSecretsResourceWithRawResponse", + "SecretsResourceWithStreamingResponse", + "AsyncSecretsResourceWithStreamingResponse", + "SSHKeysResource", + "AsyncSSHKeysResource", + "SSHKeysResourceWithRawResponse", + "AsyncSSHKeysResourceWithRawResponse", + "SSHKeysResourceWithStreamingResponse", + "AsyncSSHKeysResourceWithStreamingResponse", + "IPRangesResource", + "AsyncIPRangesResource", + "IPRangesResourceWithRawResponse", + "AsyncIPRangesResourceWithRawResponse", + "IPRangesResourceWithStreamingResponse", + "AsyncIPRangesResourceWithStreamingResponse", + "LoadBalancersResource", + "AsyncLoadBalancersResource", + "LoadBalancersResourceWithRawResponse", + "AsyncLoadBalancersResourceWithRawResponse", + "LoadBalancersResourceWithStreamingResponse", + "AsyncLoadBalancersResourceWithStreamingResponse", + "ReservedFixedIPsResource", + "AsyncReservedFixedIPsResource", + "ReservedFixedIPsResourceWithRawResponse", + "AsyncReservedFixedIPsResourceWithRawResponse", + "ReservedFixedIPsResourceWithStreamingResponse", + "AsyncReservedFixedIPsResourceWithStreamingResponse", + "NetworksResource", + "AsyncNetworksResource", + "NetworksResourceWithRawResponse", + "AsyncNetworksResourceWithRawResponse", + "NetworksResourceWithStreamingResponse", + "AsyncNetworksResourceWithStreamingResponse", + "VolumesResource", + "AsyncVolumesResource", + "VolumesResourceWithRawResponse", + "AsyncVolumesResourceWithRawResponse", + "VolumesResourceWithStreamingResponse", + "AsyncVolumesResourceWithStreamingResponse", + "FloatingIPsResource", + "AsyncFloatingIPsResource", + "FloatingIPsResourceWithRawResponse", + "AsyncFloatingIPsResourceWithRawResponse", + "FloatingIPsResourceWithStreamingResponse", + "AsyncFloatingIPsResourceWithStreamingResponse", + "SecurityGroupsResource", + "AsyncSecurityGroupsResource", + "SecurityGroupsResourceWithRawResponse", + "AsyncSecurityGroupsResourceWithRawResponse", + "SecurityGroupsResourceWithStreamingResponse", + "AsyncSecurityGroupsResourceWithStreamingResponse", + "UsersResource", + "AsyncUsersResource", + "UsersResourceWithRawResponse", + "AsyncUsersResourceWithRawResponse", + "UsersResourceWithStreamingResponse", + "AsyncUsersResourceWithStreamingResponse", + "InferenceResource", + "AsyncInferenceResource", + "InferenceResourceWithRawResponse", + "AsyncInferenceResourceWithRawResponse", + "InferenceResourceWithStreamingResponse", + "AsyncInferenceResourceWithStreamingResponse", + "PlacementGroupsResource", + "AsyncPlacementGroupsResource", + "PlacementGroupsResourceWithRawResponse", + "AsyncPlacementGroupsResourceWithRawResponse", + "PlacementGroupsResourceWithStreamingResponse", + "AsyncPlacementGroupsResourceWithStreamingResponse", + "BaremetalResource", + "AsyncBaremetalResource", + "BaremetalResourceWithRawResponse", + "AsyncBaremetalResourceWithRawResponse", + "BaremetalResourceWithStreamingResponse", + "AsyncBaremetalResourceWithStreamingResponse", + "RegistriesResource", + "AsyncRegistriesResource", + "RegistriesResourceWithRawResponse", + "AsyncRegistriesResourceWithRawResponse", + "RegistriesResourceWithStreamingResponse", + "AsyncRegistriesResourceWithStreamingResponse", + "FileSharesResource", + "AsyncFileSharesResource", + "FileSharesResourceWithRawResponse", + "AsyncFileSharesResourceWithRawResponse", + "FileSharesResourceWithStreamingResponse", + "AsyncFileSharesResourceWithStreamingResponse", + "BillingReservationsResource", + "AsyncBillingReservationsResource", + "BillingReservationsResourceWithRawResponse", + "AsyncBillingReservationsResourceWithRawResponse", + "BillingReservationsResourceWithStreamingResponse", + "AsyncBillingReservationsResourceWithStreamingResponse", + "GPUBaremetalResource", + "AsyncGPUBaremetalResource", + "GPUBaremetalResourceWithRawResponse", + "AsyncGPUBaremetalResourceWithRawResponse", + "GPUBaremetalResourceWithStreamingResponse", + "AsyncGPUBaremetalResourceWithStreamingResponse", + "GPUVirtualResource", + "AsyncGPUVirtualResource", + "GPUVirtualResourceWithRawResponse", + "AsyncGPUVirtualResourceWithRawResponse", + "GPUVirtualResourceWithStreamingResponse", + "AsyncGPUVirtualResourceWithStreamingResponse", + "InstancesResource", + "AsyncInstancesResource", + "InstancesResourceWithRawResponse", + "AsyncInstancesResourceWithRawResponse", + "InstancesResourceWithStreamingResponse", + "AsyncInstancesResourceWithStreamingResponse", + "K8SResource", + "AsyncK8SResource", + "K8SResourceWithRawResponse", + "AsyncK8SResourceWithRawResponse", + "K8SResourceWithStreamingResponse", + "AsyncK8SResourceWithStreamingResponse", + "AuditLogsResource", + "AsyncAuditLogsResource", + "AuditLogsResourceWithRawResponse", + "AsyncAuditLogsResourceWithRawResponse", + "AuditLogsResourceWithStreamingResponse", + "AsyncAuditLogsResourceWithStreamingResponse", + "CostReportsResource", + "AsyncCostReportsResource", + "CostReportsResourceWithRawResponse", + "AsyncCostReportsResourceWithRawResponse", + "CostReportsResourceWithStreamingResponse", + "AsyncCostReportsResourceWithStreamingResponse", + "UsageReportsResource", + "AsyncUsageReportsResource", + "UsageReportsResourceWithRawResponse", + "AsyncUsageReportsResourceWithRawResponse", + "UsageReportsResourceWithStreamingResponse", + "AsyncUsageReportsResourceWithStreamingResponse", + "DatabasesResource", + "AsyncDatabasesResource", + "DatabasesResourceWithRawResponse", + "AsyncDatabasesResourceWithRawResponse", + "DatabasesResourceWithStreamingResponse", + "AsyncDatabasesResourceWithStreamingResponse", + "VolumeSnapshotsResource", + "AsyncVolumeSnapshotsResource", + "VolumeSnapshotsResourceWithRawResponse", + "AsyncVolumeSnapshotsResourceWithRawResponse", + "VolumeSnapshotsResourceWithStreamingResponse", + "AsyncVolumeSnapshotsResourceWithStreamingResponse", + "CloudResource", + "AsyncCloudResource", + "CloudResourceWithRawResponse", + "AsyncCloudResourceWithRawResponse", + "CloudResourceWithStreamingResponse", + "AsyncCloudResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/api.md b/src/gcore/resources/cloud/api.md new file mode 100644 index 00000000..5e26e6a1 --- /dev/null +++ b/src/gcore/resources/cloud/api.md @@ -0,0 +1,1181 @@ +# Cloud + +Types: + +```python +from gcore.types.cloud import ( + AllowedAddressPairs, + BaremetalFlavor, + BaremetalFlavorList, + BlackholePort, + Console, + DDOSProfile, + DDOSProfileField, + DDOSProfileOptionList, + DDOSProfileStatus, + DDOSProfileTemplate, + DDOSProfileTemplateField, + FixedAddress, + FixedAddressShort, + FlavorHardwareDescription, + FloatingAddress, + FloatingIP, + FloatingIPStatus, + GPUImage, + GPUImageList, + HTTPMethod, + Image, + ImageList, + Instance, + InstanceIsolation, + InstanceList, + InstanceMetricsTimeUnit, + InterfaceIPFamily, + IPAssignment, + IPVersion, + LaasIndexRetentionPolicy, + LoadBalancer, + LoadBalancerInstanceRole, + LoadBalancerMemberConnectivity, + LoadBalancerOperatingStatus, + LoadBalancerStatistics, + Logging, + Network, + NetworkAnySubnetFip, + NetworkDetails, + NetworkInterface, + NetworkInterfaceList, + NetworkSubnetFip, + ProvisioningStatus, + Route, + Subnet, + Tag, + TagList, + TagUpdateMap, + TaskIDList, +) +``` + +## Projects + +Types: + +```python +from gcore.types.cloud import Project +``` + +Methods: + +- client.cloud.projects.create(\*\*params) -> Project +- client.cloud.projects.update(\*, project_id, \*\*params) -> Project +- client.cloud.projects.list(\*\*params) -> SyncOffsetPage[Project] +- client.cloud.projects.delete(\*, project_id) -> TaskIDList +- client.cloud.projects.get(\*, project_id) -> Project + +## Tasks + +Types: + +```python +from gcore.types.cloud import Task +``` + +Methods: + +- client.cloud.tasks.list(\*\*params) -> SyncOffsetPage[Task] +- client.cloud.tasks.acknowledge_all(\*\*params) -> None +- client.cloud.tasks.acknowledge_one(task_id) -> Task +- client.cloud.tasks.get(task_id) -> Task + +## Regions + +Types: + +```python +from gcore.types.cloud import Region +``` + +Methods: + +- client.cloud.regions.list(\*\*params) -> SyncOffsetPage[Region] +- client.cloud.regions.get(\*, region_id, \*\*params) -> Region + +## Quotas + +Types: + +```python +from gcore.types.cloud import QuotaGetAllResponse, QuotaGetByRegionResponse, QuotaGetGlobalResponse +``` + +Methods: + +- client.cloud.quotas.get_all() -> QuotaGetAllResponse +- client.cloud.quotas.get_by_region(\*, client_id, region_id) -> QuotaGetByRegionResponse +- client.cloud.quotas.get_global(client_id) -> QuotaGetGlobalResponse + +### Requests + +Types: + +```python +from gcore.types.cloud.quotas import RequestListResponse, RequestGetResponse +``` + +Methods: + +- client.cloud.quotas.requests.create(\*\*params) -> None +- client.cloud.quotas.requests.list(\*\*params) -> SyncOffsetPage[RequestListResponse] +- client.cloud.quotas.requests.delete(request_id) -> None +- client.cloud.quotas.requests.get(request_id) -> RequestGetResponse + +## Secrets + +Types: + +```python +from gcore.types.cloud import Secret +``` + +Methods: + +- client.cloud.secrets.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[Secret] +- client.cloud.secrets.delete(secret_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.secrets.get(secret_id, \*, project_id, region_id) -> Secret +- client.cloud.secrets.upload_tls_certificate(\*, project_id, region_id, \*\*params) -> TaskIDList + +## SSHKeys + +Types: + +```python +from gcore.types.cloud import SSHKey, SSHKeyCreated +``` + +Methods: + +- client.cloud.ssh_keys.create(\*, project_id, \*\*params) -> SSHKeyCreated +- client.cloud.ssh_keys.update(ssh_key_id, \*, project_id, \*\*params) -> SSHKey +- client.cloud.ssh_keys.list(\*, project_id, \*\*params) -> SyncOffsetPage[SSHKey] +- client.cloud.ssh_keys.delete(ssh_key_id, \*, project_id) -> None +- client.cloud.ssh_keys.get(ssh_key_id, \*, project_id) -> SSHKey + +## IPRanges + +Types: + +```python +from gcore.types.cloud import IPRanges +``` + +Methods: + +- client.cloud.ip_ranges.list() -> IPRanges + +## LoadBalancers + +Types: + +```python +from gcore.types.cloud import ( + HealthMonitor, + HealthMonitorStatus, + LbAlgorithm, + LbHealthMonitorType, + LbListenerProtocol, + LbPoolProtocol, + LbSessionPersistenceType, + ListenerStatus, + LoadBalancerFlavorDetail, + LoadBalancerFlavorList, + LoadBalancerL7Policy, + LoadBalancerL7PolicyList, + LoadBalancerL7Rule, + LoadBalancerL7RuleList, + LoadBalancerListenerDetail, + LoadBalancerListenerList, + LoadBalancerMetrics, + LoadBalancerMetricsList, + LoadBalancerPool, + LoadBalancerPoolList, + LoadBalancerStatus, + LoadBalancerStatusList, + Member, + MemberStatus, + PoolStatus, + SessionPersistence, +) +``` + +Methods: + +- client.cloud.load_balancers.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.load_balancers.update(load_balancer_id, \*, project_id, region_id, \*\*params) -> LoadBalancer +- client.cloud.load_balancers.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[LoadBalancer] +- client.cloud.load_balancers.delete(load_balancer_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.load_balancers.failover(load_balancer_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.load_balancers.get(load_balancer_id, \*, project_id, region_id, \*\*params) -> LoadBalancer +- client.cloud.load_balancers.resize(load_balancer_id, \*, project_id, region_id, \*\*params) -> TaskIDList + +### L7Policies + +Methods: + +- client.cloud.load_balancers.l7_policies.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.load_balancers.l7_policies.update(l7policy_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.load_balancers.l7_policies.list(\*, project_id, region_id) -> LoadBalancerL7PolicyList +- client.cloud.load_balancers.l7_policies.delete(l7policy_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.load_balancers.l7_policies.get(l7policy_id, \*, project_id, region_id) -> LoadBalancerL7Policy + +#### Rules + +Methods: + +- client.cloud.load_balancers.l7_policies.rules.create(l7policy_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.load_balancers.l7_policies.rules.list(l7policy_id, \*, project_id, region_id) -> LoadBalancerL7RuleList +- client.cloud.load_balancers.l7_policies.rules.delete(l7rule_id, \*, project_id, region_id, l7policy_id) -> TaskIDList +- client.cloud.load_balancers.l7_policies.rules.get(l7rule_id, \*, project_id, region_id, l7policy_id) -> LoadBalancerL7Rule +- client.cloud.load_balancers.l7_policies.rules.replace(l7rule_id, \*, project_id, region_id, l7policy_id, \*\*params) -> TaskIDList + +### Flavors + +Methods: + +- client.cloud.load_balancers.flavors.list(\*, project_id, region_id, \*\*params) -> LoadBalancerFlavorList + +### Listeners + +Methods: + +- client.cloud.load_balancers.listeners.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.load_balancers.listeners.update(listener_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.load_balancers.listeners.list(\*, project_id, region_id, \*\*params) -> LoadBalancerListenerList +- client.cloud.load_balancers.listeners.delete(listener_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.load_balancers.listeners.get(listener_id, \*, project_id, region_id, \*\*params) -> LoadBalancerListenerDetail + +### Pools + +Methods: + +- client.cloud.load_balancers.pools.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.load_balancers.pools.update(pool_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.load_balancers.pools.list(\*, project_id, region_id, \*\*params) -> LoadBalancerPoolList +- client.cloud.load_balancers.pools.delete(pool_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.load_balancers.pools.get(pool_id, \*, project_id, region_id) -> LoadBalancerPool + +#### HealthMonitors + +Methods: + +- client.cloud.load_balancers.pools.health_monitors.create(pool_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.load_balancers.pools.health_monitors.delete(pool_id, \*, project_id, region_id) -> None + +#### Members + +Methods: + +- client.cloud.load_balancers.pools.members.create(pool_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.load_balancers.pools.members.delete(member_id, \*, project_id, region_id, pool_id) -> TaskIDList + +### Metrics + +Methods: + +- client.cloud.load_balancers.metrics.list(load_balancer_id, \*, project_id, region_id, \*\*params) -> LoadBalancerMetricsList + +### Statuses + +Methods: + +- client.cloud.load_balancers.statuses.list(\*, project_id, region_id) -> LoadBalancerStatusList +- client.cloud.load_balancers.statuses.get(load_balancer_id, \*, project_id, region_id) -> LoadBalancerStatus + +## ReservedFixedIPs + +Types: + +```python +from gcore.types.cloud import ReservedFixedIP +``` + +Methods: + +- client.cloud.reserved_fixed_ips.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.reserved_fixed_ips.update(port_id, \*, project_id, region_id, \*\*params) -> ReservedFixedIP +- client.cloud.reserved_fixed_ips.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[ReservedFixedIP] +- client.cloud.reserved_fixed_ips.delete(port_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.reserved_fixed_ips.get(port_id, \*, project_id, region_id) -> ReservedFixedIP + +### Vip + +Types: + +```python +from gcore.types.cloud.reserved_fixed_ips import IPWithSubnet +``` + +Methods: + +- client.cloud.reserved_fixed_ips.vip.toggle(port_id, \*, project_id, region_id, \*\*params) -> ReservedFixedIP + +#### CandidatePorts + +Types: + +```python +from gcore.types.cloud.reserved_fixed_ips.vip import CandidatePort, CandidatePortList +``` + +Methods: + +- client.cloud.reserved_fixed_ips.vip.candidate_ports.list(port_id, \*, project_id, region_id) -> CandidatePortList + +#### ConnectedPorts + +Types: + +```python +from gcore.types.cloud.reserved_fixed_ips.vip import ConnectedPort, ConnectedPortList +``` + +Methods: + +- client.cloud.reserved_fixed_ips.vip.connected_ports.list(port_id, \*, project_id, region_id) -> ConnectedPortList +- client.cloud.reserved_fixed_ips.vip.connected_ports.add(port_id, \*, project_id, region_id, \*\*params) -> ConnectedPortList +- client.cloud.reserved_fixed_ips.vip.connected_ports.replace(port_id, \*, project_id, region_id, \*\*params) -> ConnectedPortList + +## Networks + +Methods: + +- client.cloud.networks.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.networks.update(network_id, \*, project_id, region_id, \*\*params) -> Network +- client.cloud.networks.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[Network] +- client.cloud.networks.delete(network_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.networks.get(network_id, \*, project_id, region_id) -> Network + +### Subnets + +Methods: + +- client.cloud.networks.subnets.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.networks.subnets.update(subnet_id, \*, project_id, region_id, \*\*params) -> Subnet +- client.cloud.networks.subnets.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[Subnet] +- client.cloud.networks.subnets.delete(subnet_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.networks.subnets.get(subnet_id, \*, project_id, region_id) -> Subnet + +### Routers + +Types: + +```python +from gcore.types.cloud.networks import Router, RouterList, SubnetID +``` + +Methods: + +- client.cloud.networks.routers.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.networks.routers.update(router_id, \*, project_id, region_id, \*\*params) -> Router +- client.cloud.networks.routers.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[Router] +- client.cloud.networks.routers.delete(router_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.networks.routers.attach_subnet(router_id, \*, project_id, region_id, \*\*params) -> Router +- client.cloud.networks.routers.detach_subnet(router_id, \*, project_id, region_id, \*\*params) -> Router +- client.cloud.networks.routers.get(router_id, \*, project_id, region_id) -> Router + +## Volumes + +Types: + +```python +from gcore.types.cloud import Volume +``` + +Methods: + +- client.cloud.volumes.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.volumes.update(volume_id, \*, project_id, region_id, \*\*params) -> Volume +- client.cloud.volumes.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[Volume] +- client.cloud.volumes.delete(volume_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.volumes.attach_to_instance(volume_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.volumes.change_type(volume_id, \*, project_id, region_id, \*\*params) -> Volume +- client.cloud.volumes.detach_from_instance(volume_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.volumes.get(volume_id, \*, project_id, region_id) -> Volume +- client.cloud.volumes.resize(volume_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.volumes.revert_to_last_snapshot(volume_id, \*, project_id, region_id) -> None + +## FloatingIPs + +Types: + +```python +from gcore.types.cloud import FloatingIPDetailed +``` + +Methods: + +- client.cloud.floating_ips.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.floating_ips.update(floating_ip_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.floating_ips.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[FloatingIPDetailed] +- client.cloud.floating_ips.delete(floating_ip_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.floating_ips.assign(floating_ip_id, \*, project_id, region_id, \*\*params) -> FloatingIP +- client.cloud.floating_ips.get(floating_ip_id, \*, project_id, region_id) -> FloatingIP +- client.cloud.floating_ips.unassign(floating_ip_id, \*, project_id, region_id) -> FloatingIP + +## SecurityGroups + +Types: + +```python +from gcore.types.cloud import SecurityGroup, SecurityGroupRule +``` + +Methods: + +- client.cloud.security_groups.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.security_groups.update(group_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.security_groups.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[SecurityGroup] +- client.cloud.security_groups.delete(group_id, \*, project_id, region_id) -> None +- client.cloud.security_groups.copy(group_id, \*, project_id, region_id, \*\*params) -> SecurityGroup +- client.cloud.security_groups.get(group_id, \*, project_id, region_id) -> SecurityGroup +- client.cloud.security_groups.revert_to_default(group_id, \*, project_id, region_id) -> SecurityGroup + +### Rules + +Methods: + +- client.cloud.security_groups.rules.create(group_id, \*, project_id, region_id, \*\*params) -> SecurityGroupRule +- client.cloud.security_groups.rules.delete(rule_id, \*, project_id, region_id) -> None +- client.cloud.security_groups.rules.replace(rule_id, \*, project_id, region_id, \*\*params) -> SecurityGroupRule + +## Users + +### RoleAssignments + +Types: + +```python +from gcore.types.cloud.users import RoleAssignment, RoleAssignmentUpdatedDeleted +``` + +Methods: + +- client.cloud.users.role_assignments.create(\*\*params) -> RoleAssignment +- client.cloud.users.role_assignments.update(assignment_id, \*\*params) -> RoleAssignmentUpdatedDeleted +- client.cloud.users.role_assignments.list(\*\*params) -> SyncOffsetPage[RoleAssignment] +- client.cloud.users.role_assignments.delete(assignment_id) -> RoleAssignmentUpdatedDeleted + +## Inference + +Types: + +```python +from gcore.types.cloud import InferenceRegionCapacity, InferenceRegionCapacityList +``` + +Methods: + +- client.cloud.inference.get_capacity_by_region() -> InferenceRegionCapacityList + +### Flavors + +Types: + +```python +from gcore.types.cloud.inference import InferenceFlavor +``` + +Methods: + +- client.cloud.inference.flavors.list(\*\*params) -> SyncOffsetPage[InferenceFlavor] +- client.cloud.inference.flavors.get(flavor_name) -> InferenceFlavor + +### Deployments + +Types: + +```python +from gcore.types.cloud.inference import ( + InferenceDeployment, + InferenceDeploymentAPIKey, + Probe, + ProbeConfig, + ProbeExec, + ProbeHTTPGet, + ProbeTcpSocket, +) +``` + +Methods: + +- client.cloud.inference.deployments.create(\*, project_id, \*\*params) -> TaskIDList +- client.cloud.inference.deployments.update(deployment_name, \*, project_id, \*\*params) -> TaskIDList +- client.cloud.inference.deployments.list(\*, project_id, \*\*params) -> SyncOffsetPage[InferenceDeployment] +- client.cloud.inference.deployments.delete(deployment_name, \*, project_id) -> TaskIDList +- client.cloud.inference.deployments.get(deployment_name, \*, project_id) -> InferenceDeployment +- client.cloud.inference.deployments.get_api_key(deployment_name, \*, project_id) -> InferenceDeploymentAPIKey +- client.cloud.inference.deployments.start(deployment_name, \*, project_id) -> None +- client.cloud.inference.deployments.stop(deployment_name, \*, project_id) -> None + +#### Logs + +Types: + +```python +from gcore.types.cloud.inference.deployments import InferenceDeploymentLog +``` + +Methods: + +- client.cloud.inference.deployments.logs.list(deployment_name, \*, project_id, \*\*params) -> SyncOffsetPage[InferenceDeploymentLog] + +### RegistryCredentials + +Types: + +```python +from gcore.types.cloud.inference import InferenceRegistryCredentials +``` + +Methods: + +- client.cloud.inference.registry_credentials.create(\*, project_id, \*\*params) -> InferenceRegistryCredentials +- client.cloud.inference.registry_credentials.list(\*, project_id, \*\*params) -> SyncOffsetPage[InferenceRegistryCredentials] +- client.cloud.inference.registry_credentials.delete(credential_name, \*, project_id) -> None +- client.cloud.inference.registry_credentials.get(credential_name, \*, project_id) -> InferenceRegistryCredentials +- client.cloud.inference.registry_credentials.replace(credential_name, \*, project_id, \*\*params) -> InferenceRegistryCredentials + +### Secrets + +Types: + +```python +from gcore.types.cloud.inference import InferenceSecret +``` + +Methods: + +- client.cloud.inference.secrets.create(\*, project_id, \*\*params) -> InferenceSecret +- client.cloud.inference.secrets.list(\*, project_id, \*\*params) -> SyncOffsetPage[InferenceSecret] +- client.cloud.inference.secrets.delete(secret_name, \*, project_id) -> None +- client.cloud.inference.secrets.get(secret_name, \*, project_id) -> InferenceSecret +- client.cloud.inference.secrets.replace(secret_name, \*, project_id, \*\*params) -> InferenceSecret + +### APIKeys + +Types: + +```python +from gcore.types.cloud.inference import InferenceAPIKey, InferenceAPIKeyCreated +``` + +Methods: + +- client.cloud.inference.api_keys.create(\*, project_id, \*\*params) -> InferenceAPIKeyCreated +- client.cloud.inference.api_keys.update(api_key_name, \*, project_id, \*\*params) -> InferenceAPIKey +- client.cloud.inference.api_keys.list(\*, project_id, \*\*params) -> SyncOffsetPage[InferenceAPIKey] +- client.cloud.inference.api_keys.delete(api_key_name, \*, project_id) -> None +- client.cloud.inference.api_keys.get(api_key_name, \*, project_id) -> InferenceAPIKey + +### Applications + +#### Deployments + +Types: + +```python +from gcore.types.cloud.inference.applications import ( + InferenceApplicationDeployment, + InferenceApplicationDeploymentList, +) +``` + +Methods: + +- client.cloud.inference.applications.deployments.create(\*, project_id, \*\*params) -> TaskIDList +- client.cloud.inference.applications.deployments.update(deployment_name, \*, project_id, \*\*params) -> TaskIDList +- client.cloud.inference.applications.deployments.list(\*, project_id) -> InferenceApplicationDeploymentList +- client.cloud.inference.applications.deployments.delete(deployment_name, \*, project_id) -> TaskIDList +- client.cloud.inference.applications.deployments.get(deployment_name, \*, project_id) -> InferenceApplicationDeployment + +#### Templates + +Types: + +```python +from gcore.types.cloud.inference.applications import ( + InferenceApplicationTemplate, + InferenceApplicationTemplateList, +) +``` + +Methods: + +- client.cloud.inference.applications.templates.list() -> InferenceApplicationTemplateList +- client.cloud.inference.applications.templates.get(application_name) -> InferenceApplicationTemplate + +## PlacementGroups + +Types: + +```python +from gcore.types.cloud import PlacementGroup, PlacementGroupList +``` + +Methods: + +- client.cloud.placement_groups.create(\*, project_id, region_id, \*\*params) -> PlacementGroup +- client.cloud.placement_groups.list(\*, project_id, region_id) -> PlacementGroupList +- client.cloud.placement_groups.delete(group_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.placement_groups.get(group_id, \*, project_id, region_id) -> PlacementGroup + +## Baremetal + +### Images + +Methods: + +- client.cloud.baremetal.images.list(\*, project_id, region_id, \*\*params) -> ImageList + +### Flavors + +Methods: + +- client.cloud.baremetal.flavors.list(\*, project_id, region_id, \*\*params) -> BaremetalFlavorList + +### Servers + +Types: + +```python +from gcore.types.cloud.baremetal import ( + BaremetalFixedAddress, + BaremetalFloatingAddress, + BaremetalServer, +) +``` + +Methods: + +- client.cloud.baremetal.servers.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.baremetal.servers.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[BaremetalServer] +- client.cloud.baremetal.servers.rebuild(server_id, \*, project_id, region_id, \*\*params) -> TaskIDList + +## Registries + +Types: + +```python +from gcore.types.cloud import Registry, RegistryList, RegistryTag +``` + +Methods: + +- client.cloud.registries.create(\*, project_id, region_id, \*\*params) -> Registry +- client.cloud.registries.list(\*, project_id, region_id) -> RegistryList +- client.cloud.registries.delete(registry_id, \*, project_id, region_id) -> None +- client.cloud.registries.get(registry_id, \*, project_id, region_id) -> Registry +- client.cloud.registries.resize(registry_id, \*, project_id, region_id, \*\*params) -> Registry + +### Repositories + +Types: + +```python +from gcore.types.cloud.registries import RegistryRepository, RegistryRepositoryList +``` + +Methods: + +- client.cloud.registries.repositories.list(registry_id, \*, project_id, region_id) -> RegistryRepositoryList +- client.cloud.registries.repositories.delete(repository_name, \*, project_id, region_id, registry_id) -> None + +### Artifacts + +Types: + +```python +from gcore.types.cloud.registries import RegistryArtifact, RegistryArtifactList +``` + +Methods: + +- client.cloud.registries.artifacts.list(repository_name, \*, project_id, region_id, registry_id) -> RegistryArtifactList +- client.cloud.registries.artifacts.delete(digest, \*, project_id, region_id, registry_id, repository_name) -> None + +### Tags + +Methods: + +- client.cloud.registries.tags.delete(tag_name, \*, project_id, region_id, registry_id, repository_name, digest) -> None + +### Users + +Types: + +```python +from gcore.types.cloud.registries import ( + RegistryUser, + RegistryUserCreated, + RegistryUserList, + UserRefreshSecretResponse, +) +``` + +Methods: + +- client.cloud.registries.users.create(registry_id, \*, project_id, region_id, \*\*params) -> RegistryUserCreated +- client.cloud.registries.users.update(user_id, \*, project_id, region_id, registry_id, \*\*params) -> RegistryUser +- client.cloud.registries.users.list(registry_id, \*, project_id, region_id) -> RegistryUserList +- client.cloud.registries.users.delete(user_id, \*, project_id, region_id, registry_id) -> None +- client.cloud.registries.users.create_multiple(registry_id, \*, project_id, region_id, \*\*params) -> RegistryUserCreated +- client.cloud.registries.users.refresh_secret(user_id, \*, project_id, region_id, registry_id) -> UserRefreshSecretResponse + +## FileShares + +Types: + +```python +from gcore.types.cloud import FileShare +``` + +Methods: + +- client.cloud.file_shares.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.file_shares.update(file_share_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.file_shares.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[FileShare] +- client.cloud.file_shares.delete(file_share_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.file_shares.get(file_share_id, \*, project_id, region_id) -> FileShare +- client.cloud.file_shares.resize(file_share_id, \*, project_id, region_id, \*\*params) -> TaskIDList + +### AccessRules + +Types: + +```python +from gcore.types.cloud.file_shares import AccessRule, AccessRuleList +``` + +Methods: + +- client.cloud.file_shares.access_rules.create(file_share_id, \*, project_id, region_id, \*\*params) -> AccessRule +- client.cloud.file_shares.access_rules.list(file_share_id, \*, project_id, region_id) -> AccessRuleList +- client.cloud.file_shares.access_rules.delete(access_rule_id, \*, project_id, region_id, file_share_id) -> None + +## BillingReservations + +Types: + +```python +from gcore.types.cloud import BillingReservation, BillingReservations +``` + +Methods: + +- client.cloud.billing_reservations.list(\*\*params) -> BillingReservations + +## GPUBaremetal + +### Clusters + +Types: + +```python +from gcore.types.cloud.gpu_baremetal import GPUBaremetalCluster +``` + +Methods: + +- client.cloud.gpu_baremetal.clusters.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.gpu_baremetal.clusters.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[GPUBaremetalCluster] +- client.cloud.gpu_baremetal.clusters.delete(cluster_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.gpu_baremetal.clusters.action(cluster_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.gpu_baremetal.clusters.get(cluster_id, \*, project_id, region_id) -> GPUBaremetalCluster +- client.cloud.gpu_baremetal.clusters.powercycle_all_servers(cluster_id, \*, project_id, region_id) -> GPUBaremetalClusterServerV1List +- client.cloud.gpu_baremetal.clusters.reboot_all_servers(cluster_id, \*, project_id, region_id) -> GPUBaremetalClusterServerV1List +- client.cloud.gpu_baremetal.clusters.rebuild(cluster_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.gpu_baremetal.clusters.resize(cluster_id, \*, project_id, region_id, \*\*params) -> TaskIDList + +#### Interfaces + +Methods: + +- client.cloud.gpu_baremetal.clusters.interfaces.list(cluster_id, \*, project_id, region_id) -> NetworkInterfaceList +- client.cloud.gpu_baremetal.clusters.interfaces.attach(instance_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.gpu_baremetal.clusters.interfaces.detach(instance_id, \*, project_id, region_id, \*\*params) -> TaskIDList + +#### Servers + +Types: + +```python +from gcore.types.cloud.gpu_baremetal.clusters import ( + GPUBaremetalClusterServer, + GPUBaremetalClusterServerV1, + GPUBaremetalClusterServerV1List, +) +``` + +Methods: + +- client.cloud.gpu_baremetal.clusters.servers.list(cluster_id, \*, project_id, region_id, \*\*params) -> SyncOffsetPage[GPUBaremetalClusterServer] +- client.cloud.gpu_baremetal.clusters.servers.delete(instance_id, \*, project_id, region_id, cluster_id, \*\*params) -> TaskIDList +- client.cloud.gpu_baremetal.clusters.servers.get_console(instance_id, \*, project_id, region_id) -> Console +- client.cloud.gpu_baremetal.clusters.servers.powercycle(instance_id, \*, project_id, region_id) -> GPUBaremetalClusterServerV1 +- client.cloud.gpu_baremetal.clusters.servers.reboot(instance_id, \*, project_id, region_id) -> GPUBaremetalClusterServerV1 + +#### Flavors + +Types: + +```python +from gcore.types.cloud.gpu_baremetal.clusters import GPUBaremetalFlavor, GPUBaremetalFlavorList +``` + +Methods: + +- client.cloud.gpu_baremetal.clusters.flavors.list(\*, project_id, region_id, \*\*params) -> GPUBaremetalFlavorList + +#### Images + +Methods: + +- client.cloud.gpu_baremetal.clusters.images.list(\*, project_id, region_id) -> GPUImageList +- client.cloud.gpu_baremetal.clusters.images.delete(image_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.gpu_baremetal.clusters.images.get(image_id, \*, project_id, region_id) -> GPUImage +- client.cloud.gpu_baremetal.clusters.images.upload(\*, project_id, region_id, \*\*params) -> TaskIDList + +## GPUVirtual + +### Clusters + +Types: + +```python +from gcore.types.cloud.gpu_virtual import GPUVirtualCluster +``` + +Methods: + +- client.cloud.gpu_virtual.clusters.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.gpu_virtual.clusters.update(cluster_id, \*, project_id, region_id, \*\*params) -> GPUVirtualCluster +- client.cloud.gpu_virtual.clusters.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[GPUVirtualCluster] +- client.cloud.gpu_virtual.clusters.delete(cluster_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.gpu_virtual.clusters.action(cluster_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.gpu_virtual.clusters.get(cluster_id, \*, project_id, region_id) -> GPUVirtualCluster + +#### Servers + +Types: + +```python +from gcore.types.cloud.gpu_virtual.clusters import ( + GPUVirtualClusterServer, + GPUVirtualClusterServerList, +) +``` + +Methods: + +- client.cloud.gpu_virtual.clusters.servers.list(cluster_id, \*, project_id, region_id, \*\*params) -> GPUVirtualClusterServerList +- client.cloud.gpu_virtual.clusters.servers.delete(server_id, \*, project_id, region_id, cluster_id, \*\*params) -> TaskIDList + +#### Volumes + +Types: + +```python +from gcore.types.cloud.gpu_virtual.clusters import ( + GPUVirtualClusterVolume, + GPUVirtualClusterVolumeList, +) +``` + +Methods: + +- client.cloud.gpu_virtual.clusters.volumes.list(cluster_id, \*, project_id, region_id) -> GPUVirtualClusterVolumeList + +#### Interfaces + +Types: + +```python +from gcore.types.cloud.gpu_virtual.clusters import GPUVirtualInterface, GPUVirtualInterfaceList +``` + +Methods: + +- client.cloud.gpu_virtual.clusters.interfaces.list(cluster_id, \*, project_id, region_id) -> GPUVirtualInterfaceList + +#### Flavors + +Types: + +```python +from gcore.types.cloud.gpu_virtual.clusters import GPUVirtualFlavor, GPUVirtualFlavorList +``` + +Methods: + +- client.cloud.gpu_virtual.clusters.flavors.list(\*, project_id, region_id, \*\*params) -> GPUVirtualFlavorList + +#### Images + +Methods: + +- client.cloud.gpu_virtual.clusters.images.list(\*, project_id, region_id) -> GPUImageList +- client.cloud.gpu_virtual.clusters.images.delete(image_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.gpu_virtual.clusters.images.get(image_id, \*, project_id, region_id) -> GPUImage +- client.cloud.gpu_virtual.clusters.images.upload(\*, project_id, region_id, \*\*params) -> TaskIDList + +## Instances + +Types: + +```python +from gcore.types.cloud import InstanceInterface +``` + +Methods: + +- client.cloud.instances.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.instances.update(instance_id, \*, project_id, region_id, \*\*params) -> Instance +- client.cloud.instances.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[Instance] +- client.cloud.instances.delete(instance_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.instances.action(instance_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.instances.add_to_placement_group(instance_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.instances.assign_security_group(instance_id, \*, project_id, region_id, \*\*params) -> None +- client.cloud.instances.disable_port_security(port_id, \*, project_id, region_id) -> InstanceInterface +- client.cloud.instances.enable_port_security(port_id, \*, project_id, region_id) -> InstanceInterface +- client.cloud.instances.get(instance_id, \*, project_id, region_id) -> Instance +- client.cloud.instances.get_console(instance_id, \*, project_id, region_id, \*\*params) -> Console +- client.cloud.instances.remove_from_placement_group(instance_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.instances.resize(instance_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.instances.unassign_security_group(instance_id, \*, project_id, region_id, \*\*params) -> None + +### Flavors + +Types: + +```python +from gcore.types.cloud.instances import InstanceFlavorDetailed, InstanceFlavorList +``` + +Methods: + +- client.cloud.instances.flavors.list(\*, project_id, region_id, \*\*params) -> InstanceFlavorList + +### Interfaces + +Methods: + +- client.cloud.instances.interfaces.list(instance_id, \*, project_id, region_id) -> NetworkInterfaceList +- client.cloud.instances.interfaces.attach(instance_id, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.instances.interfaces.detach(instance_id, \*, project_id, region_id, \*\*params) -> TaskIDList + +### Images + +Methods: + +- client.cloud.instances.images.update(image_id, \*, project_id, region_id, \*\*params) -> Image +- client.cloud.instances.images.list(\*, project_id, region_id, \*\*params) -> ImageList +- client.cloud.instances.images.delete(image_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.instances.images.create_from_volume(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.instances.images.get(image_id, \*, project_id, region_id, \*\*params) -> Image +- client.cloud.instances.images.upload(\*, project_id, region_id, \*\*params) -> TaskIDList + +### Metrics + +Types: + +```python +from gcore.types.cloud.instances import Metrics, MetricsList +``` + +Methods: + +- client.cloud.instances.metrics.list(instance_id, \*, project_id, region_id, \*\*params) -> MetricsList + +## K8S + +Types: + +```python +from gcore.types.cloud import K8SClusterVersion, K8SClusterVersionList +``` + +Methods: + +- client.cloud.k8s.list_versions(\*, project_id, region_id) -> K8SClusterVersionList + +### Flavors + +Methods: + +- client.cloud.k8s.flavors.list(\*, project_id, region_id, \*\*params) -> BaremetalFlavorList + +### Clusters + +Types: + +```python +from gcore.types.cloud.k8s import ( + K8SCluster, + K8SClusterCertificate, + K8SClusterKubeconfig, + K8SClusterList, +) +``` + +Methods: + +- client.cloud.k8s.clusters.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.k8s.clusters.update(cluster_name, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.k8s.clusters.list(\*, project_id, region_id) -> K8SClusterList +- client.cloud.k8s.clusters.delete(cluster_name, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.k8s.clusters.get(cluster_name, \*, project_id, region_id) -> K8SCluster +- client.cloud.k8s.clusters.get_certificate(cluster_name, \*, project_id, region_id) -> K8SClusterCertificate +- client.cloud.k8s.clusters.get_kubeconfig(cluster_name, \*, project_id, region_id) -> K8SClusterKubeconfig +- client.cloud.k8s.clusters.list_versions_for_upgrade(cluster_name, \*, project_id, region_id) -> K8SClusterVersionList +- client.cloud.k8s.clusters.upgrade(cluster_name, \*, project_id, region_id, \*\*params) -> TaskIDList + +#### Nodes + +Methods: + +- client.cloud.k8s.clusters.nodes.list(cluster_name, \*, project_id, region_id, \*\*params) -> InstanceList +- client.cloud.k8s.clusters.nodes.delete(instance_id, \*, project_id, region_id, cluster_name) -> None + +#### Pools + +Types: + +```python +from gcore.types.cloud.k8s.clusters import K8SClusterPool, K8SClusterPoolList, K8SClusterPoolQuota +``` + +Methods: + +- client.cloud.k8s.clusters.pools.create(cluster_name, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.k8s.clusters.pools.update(pool_name, \*, project_id, region_id, cluster_name, \*\*params) -> K8SClusterPool +- client.cloud.k8s.clusters.pools.list(cluster_name, \*, project_id, region_id) -> K8SClusterPoolList +- client.cloud.k8s.clusters.pools.delete(pool_name, \*, project_id, region_id, cluster_name) -> TaskIDList +- client.cloud.k8s.clusters.pools.check_quota(\*, project_id, region_id, \*\*params) -> K8SClusterPoolQuota +- client.cloud.k8s.clusters.pools.get(pool_name, \*, project_id, region_id, cluster_name) -> K8SClusterPool +- client.cloud.k8s.clusters.pools.resize(pool_name, \*, project_id, region_id, cluster_name, \*\*params) -> TaskIDList + +##### Nodes + +Methods: + +- client.cloud.k8s.clusters.pools.nodes.list(pool_name, \*, project_id, region_id, cluster_name, \*\*params) -> InstanceList +- client.cloud.k8s.clusters.pools.nodes.delete(instance_id, \*, project_id, region_id, cluster_name, pool_name) -> None + +## AuditLogs + +Types: + +```python +from gcore.types.cloud import AuditLogEntry +``` + +Methods: + +- client.cloud.audit_logs.list(\*\*params) -> SyncOffsetPage[AuditLogEntry] + +## CostReports + +Types: + +```python +from gcore.types.cloud import CostReportAggregated, CostReportAggregatedMonthly, CostReportDetailed +``` + +Methods: + +- client.cloud.cost_reports.get_aggregated(\*\*params) -> CostReportAggregated +- client.cloud.cost_reports.get_aggregated_monthly(\*\*params) -> CostReportAggregatedMonthly +- client.cloud.cost_reports.get_detailed(\*\*params) -> CostReportDetailed + +## UsageReports + +Types: + +```python +from gcore.types.cloud import UsageReport +``` + +Methods: + +- client.cloud.usage_reports.get(\*\*params) -> UsageReport + +## Databases + +### Postgres + +#### Clusters + +Types: + +```python +from gcore.types.cloud.databases.postgres import PostgresCluster, PostgresClusterShort +``` + +Methods: + +- client.cloud.databases.postgres.clusters.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.databases.postgres.clusters.update(cluster_name, \*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.databases.postgres.clusters.list(\*, project_id, region_id, \*\*params) -> SyncOffsetPage[PostgresClusterShort] +- client.cloud.databases.postgres.clusters.delete(cluster_name, \*, project_id, region_id) -> TaskIDList +- client.cloud.databases.postgres.clusters.get(cluster_name, \*, project_id, region_id) -> PostgresCluster + +##### UserCredentials + +Types: + +```python +from gcore.types.cloud.databases.postgres.clusters import PostgresUserCredentials +``` + +Methods: + +- client.cloud.databases.postgres.clusters.user_credentials.get(username, \*, project_id, region_id, cluster_name) -> PostgresUserCredentials +- client.cloud.databases.postgres.clusters.user_credentials.regenerate(username, \*, project_id, region_id, cluster_name) -> PostgresUserCredentials + +#### Configurations + +Types: + +```python +from gcore.types.cloud.databases.postgres import PostgresConfiguration +``` + +Methods: + +- client.cloud.databases.postgres.configurations.get(\*, project_id, region_id) -> PostgresConfiguration + +#### CustomConfigurations + +Types: + +```python +from gcore.types.cloud.databases.postgres import PgConfValidation +``` + +Methods: + +- client.cloud.databases.postgres.custom_configurations.validate(\*, project_id, region_id, \*\*params) -> PgConfValidation + +## VolumeSnapshots + +Types: + +```python +from gcore.types.cloud import Snapshot +``` + +Methods: + +- client.cloud.volume_snapshots.create(\*, project_id, region_id, \*\*params) -> TaskIDList +- client.cloud.volume_snapshots.update(snapshot_id, \*, project_id, region_id, \*\*params) -> Snapshot +- client.cloud.volume_snapshots.delete(snapshot_id, \*, project_id, region_id) -> TaskIDList +- client.cloud.volume_snapshots.get(snapshot_id, \*, project_id, region_id) -> Snapshot diff --git a/src/gcore/resources/cloud/audit_logs.py b/src/gcore/resources/cloud/audit_logs.py new file mode 100644 index 00000000..bca05f96 --- /dev/null +++ b/src/gcore/resources/cloud/audit_logs.py @@ -0,0 +1,498 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ...types.cloud import audit_log_list_params +from ..._base_client import AsyncPaginator, make_request_options +from ...types.cloud.audit_log_entry import AuditLogEntry + +__all__ = ["AuditLogsResource", "AsyncAuditLogsResource"] + + +class AuditLogsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> AuditLogsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AuditLogsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AuditLogsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AuditLogsResourceWithStreamingResponse(self) + + def list( + self, + *, + action_type: List[ + Literal[ + "activate", + "attach", + "change_logging_resources", + "create", + "create_access_rule", + "deactivate", + "delete", + "delete_access_rule", + "delete_metadata", + "detach", + "disable_logging", + "disable_portsecurity", + "download", + "enable_logging", + "enable_portsecurity", + "failover", + "put_into_servergroup", + "reboot", + "reboot_hard", + "rebuild", + "regenerate_credentials", + "remove_from_servergroup", + "replace_metadata", + "resize", + "resume", + "retype", + "revert", + "scale_down", + "scale_up", + "start", + "stop", + "suspend", + "update", + "update_metadata", + "upgrade", + ] + ] + | Omit = omit, + api_group: List[ + Literal[ + "ai_cluster", + "caas_container", + "caas_key", + "caas_pull_secret", + "dbaas_postgres", + "ddos_profile", + "faas_function", + "faas_key", + "faas_namespace", + "file_shares", + "floating_ip", + "image", + "inference_at_the_edge", + "instance", + "instance_isolation", + "k8s_cluster", + "k8s_cluster_template", + "k8s_pool", + "laas", + "laas_topic", + "lb_health_monitor", + "lb_l7policy", + "lb_l7rule", + "lblistener", + "lbpool", + "lbpool_member", + "lifecycle_policy", + "lifecycle_policy_volume_member", + "loadbalancer", + "network", + "port", + "project", + "quota_limit_request", + "registry", + "reservation", + "reserved_fixed_ip", + "role", + "router", + "secret", + "securitygroup", + "securitygrouprule", + "servergroup", + "shared_flavor", + "shared_image", + "shared_network", + "snapshot", + "snapshot_schedule", + "ssh_key", + "subnet", + "user", + "vip_ip_addresses", + "volume", + ] + ] + | Omit = omit, + from_timestamp: Union[str, datetime] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["asc", "desc"] | Omit = omit, + project_id: Iterable[int] | Omit = omit, + region_id: Iterable[int] | Omit = omit, + resource_id: SequenceNotStr[str] | Omit = omit, + search_field: str | Omit = omit, + sorting: Literal["asc", "desc"] | Omit = omit, + source_user_ips: SequenceNotStr[str] | Omit = omit, + to_timestamp: Union[str, datetime] | Omit = omit, + user_agents: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[AuditLogEntry]: + """ + Retrieve user action log for one client or a set of projects + + Args: + action_type: User action type. Several options can be specified. + + api_group: API group that requested action belongs to. Several options can be specified. + + from_timestamp: ISO formatted datetime string. Starting timestamp from which user actions are + requested + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + order_by: Sorting by timestamp. Oldest first, or most recent first + + project_id: Project ID. Several options can be specified. + + region_id: Region ID. Several options can be specified. + + resource_id: Resource ID. Several options can be specified. + + search_field: Extra search field for common object properties such as name, IP address, or + other, depending on the `resource_type` + + sorting: (DEPRECATED Use 'order_by' instead) Sorting by timestamp. Oldest first, or most + recent first + + source_user_ips: Originating IP address of the client making the request. Several options can be + specified. + + to_timestamp: ISO formatted datetime string. Ending timestamp until which user actions are + requested + + user_agents: User-Agent string identifying the client making the request. Several options can + be specified. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v1/user_actions", + page=SyncOffsetPage[AuditLogEntry], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "action_type": action_type, + "api_group": api_group, + "from_timestamp": from_timestamp, + "limit": limit, + "offset": offset, + "order_by": order_by, + "project_id": project_id, + "region_id": region_id, + "resource_id": resource_id, + "search_field": search_field, + "sorting": sorting, + "source_user_ips": source_user_ips, + "to_timestamp": to_timestamp, + "user_agents": user_agents, + }, + audit_log_list_params.AuditLogListParams, + ), + ), + model=AuditLogEntry, + ) + + +class AsyncAuditLogsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAuditLogsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncAuditLogsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAuditLogsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncAuditLogsResourceWithStreamingResponse(self) + + def list( + self, + *, + action_type: List[ + Literal[ + "activate", + "attach", + "change_logging_resources", + "create", + "create_access_rule", + "deactivate", + "delete", + "delete_access_rule", + "delete_metadata", + "detach", + "disable_logging", + "disable_portsecurity", + "download", + "enable_logging", + "enable_portsecurity", + "failover", + "put_into_servergroup", + "reboot", + "reboot_hard", + "rebuild", + "regenerate_credentials", + "remove_from_servergroup", + "replace_metadata", + "resize", + "resume", + "retype", + "revert", + "scale_down", + "scale_up", + "start", + "stop", + "suspend", + "update", + "update_metadata", + "upgrade", + ] + ] + | Omit = omit, + api_group: List[ + Literal[ + "ai_cluster", + "caas_container", + "caas_key", + "caas_pull_secret", + "dbaas_postgres", + "ddos_profile", + "faas_function", + "faas_key", + "faas_namespace", + "file_shares", + "floating_ip", + "image", + "inference_at_the_edge", + "instance", + "instance_isolation", + "k8s_cluster", + "k8s_cluster_template", + "k8s_pool", + "laas", + "laas_topic", + "lb_health_monitor", + "lb_l7policy", + "lb_l7rule", + "lblistener", + "lbpool", + "lbpool_member", + "lifecycle_policy", + "lifecycle_policy_volume_member", + "loadbalancer", + "network", + "port", + "project", + "quota_limit_request", + "registry", + "reservation", + "reserved_fixed_ip", + "role", + "router", + "secret", + "securitygroup", + "securitygrouprule", + "servergroup", + "shared_flavor", + "shared_image", + "shared_network", + "snapshot", + "snapshot_schedule", + "ssh_key", + "subnet", + "user", + "vip_ip_addresses", + "volume", + ] + ] + | Omit = omit, + from_timestamp: Union[str, datetime] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["asc", "desc"] | Omit = omit, + project_id: Iterable[int] | Omit = omit, + region_id: Iterable[int] | Omit = omit, + resource_id: SequenceNotStr[str] | Omit = omit, + search_field: str | Omit = omit, + sorting: Literal["asc", "desc"] | Omit = omit, + source_user_ips: SequenceNotStr[str] | Omit = omit, + to_timestamp: Union[str, datetime] | Omit = omit, + user_agents: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[AuditLogEntry, AsyncOffsetPage[AuditLogEntry]]: + """ + Retrieve user action log for one client or a set of projects + + Args: + action_type: User action type. Several options can be specified. + + api_group: API group that requested action belongs to. Several options can be specified. + + from_timestamp: ISO formatted datetime string. Starting timestamp from which user actions are + requested + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + order_by: Sorting by timestamp. Oldest first, or most recent first + + project_id: Project ID. Several options can be specified. + + region_id: Region ID. Several options can be specified. + + resource_id: Resource ID. Several options can be specified. + + search_field: Extra search field for common object properties such as name, IP address, or + other, depending on the `resource_type` + + sorting: (DEPRECATED Use 'order_by' instead) Sorting by timestamp. Oldest first, or most + recent first + + source_user_ips: Originating IP address of the client making the request. Several options can be + specified. + + to_timestamp: ISO formatted datetime string. Ending timestamp until which user actions are + requested + + user_agents: User-Agent string identifying the client making the request. Several options can + be specified. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v1/user_actions", + page=AsyncOffsetPage[AuditLogEntry], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "action_type": action_type, + "api_group": api_group, + "from_timestamp": from_timestamp, + "limit": limit, + "offset": offset, + "order_by": order_by, + "project_id": project_id, + "region_id": region_id, + "resource_id": resource_id, + "search_field": search_field, + "sorting": sorting, + "source_user_ips": source_user_ips, + "to_timestamp": to_timestamp, + "user_agents": user_agents, + }, + audit_log_list_params.AuditLogListParams, + ), + ), + model=AuditLogEntry, + ) + + +class AuditLogsResourceWithRawResponse: + def __init__(self, audit_logs: AuditLogsResource) -> None: + self._audit_logs = audit_logs + + self.list = to_raw_response_wrapper( + audit_logs.list, + ) + + +class AsyncAuditLogsResourceWithRawResponse: + def __init__(self, audit_logs: AsyncAuditLogsResource) -> None: + self._audit_logs = audit_logs + + self.list = async_to_raw_response_wrapper( + audit_logs.list, + ) + + +class AuditLogsResourceWithStreamingResponse: + def __init__(self, audit_logs: AuditLogsResource) -> None: + self._audit_logs = audit_logs + + self.list = to_streamed_response_wrapper( + audit_logs.list, + ) + + +class AsyncAuditLogsResourceWithStreamingResponse: + def __init__(self, audit_logs: AsyncAuditLogsResource) -> None: + self._audit_logs = audit_logs + + self.list = async_to_streamed_response_wrapper( + audit_logs.list, + ) diff --git a/src/gcore/resources/cloud/baremetal/__init__.py b/src/gcore/resources/cloud/baremetal/__init__.py new file mode 100644 index 00000000..f122cad9 --- /dev/null +++ b/src/gcore/resources/cloud/baremetal/__init__.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .images import ( + ImagesResource, + AsyncImagesResource, + ImagesResourceWithRawResponse, + AsyncImagesResourceWithRawResponse, + ImagesResourceWithStreamingResponse, + AsyncImagesResourceWithStreamingResponse, +) +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from .servers import ( + ServersResource, + AsyncServersResource, + ServersResourceWithRawResponse, + AsyncServersResourceWithRawResponse, + ServersResourceWithStreamingResponse, + AsyncServersResourceWithStreamingResponse, +) +from .baremetal import ( + BaremetalResource, + AsyncBaremetalResource, + BaremetalResourceWithRawResponse, + AsyncBaremetalResourceWithRawResponse, + BaremetalResourceWithStreamingResponse, + AsyncBaremetalResourceWithStreamingResponse, +) + +__all__ = [ + "ImagesResource", + "AsyncImagesResource", + "ImagesResourceWithRawResponse", + "AsyncImagesResourceWithRawResponse", + "ImagesResourceWithStreamingResponse", + "AsyncImagesResourceWithStreamingResponse", + "FlavorsResource", + "AsyncFlavorsResource", + "FlavorsResourceWithRawResponse", + "AsyncFlavorsResourceWithRawResponse", + "FlavorsResourceWithStreamingResponse", + "AsyncFlavorsResourceWithStreamingResponse", + "ServersResource", + "AsyncServersResource", + "ServersResourceWithRawResponse", + "AsyncServersResourceWithRawResponse", + "ServersResourceWithStreamingResponse", + "AsyncServersResourceWithStreamingResponse", + "BaremetalResource", + "AsyncBaremetalResource", + "BaremetalResourceWithRawResponse", + "AsyncBaremetalResourceWithRawResponse", + "BaremetalResourceWithStreamingResponse", + "AsyncBaremetalResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/baremetal/baremetal.py b/src/gcore/resources/cloud/baremetal/baremetal.py new file mode 100644 index 00000000..6922c20d --- /dev/null +++ b/src/gcore/resources/cloud/baremetal/baremetal.py @@ -0,0 +1,166 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .images import ( + ImagesResource, + AsyncImagesResource, + ImagesResourceWithRawResponse, + AsyncImagesResourceWithRawResponse, + ImagesResourceWithStreamingResponse, + AsyncImagesResourceWithStreamingResponse, +) +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from .servers import ( + ServersResource, + AsyncServersResource, + ServersResourceWithRawResponse, + AsyncServersResourceWithRawResponse, + ServersResourceWithStreamingResponse, + AsyncServersResourceWithStreamingResponse, +) +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource + +__all__ = ["BaremetalResource", "AsyncBaremetalResource"] + + +class BaremetalResource(SyncAPIResource): + @cached_property + def images(self) -> ImagesResource: + return ImagesResource(self._client) + + @cached_property + def flavors(self) -> FlavorsResource: + return FlavorsResource(self._client) + + @cached_property + def servers(self) -> ServersResource: + return ServersResource(self._client) + + @cached_property + def with_raw_response(self) -> BaremetalResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return BaremetalResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BaremetalResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return BaremetalResourceWithStreamingResponse(self) + + +class AsyncBaremetalResource(AsyncAPIResource): + @cached_property + def images(self) -> AsyncImagesResource: + return AsyncImagesResource(self._client) + + @cached_property + def flavors(self) -> AsyncFlavorsResource: + return AsyncFlavorsResource(self._client) + + @cached_property + def servers(self) -> AsyncServersResource: + return AsyncServersResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncBaremetalResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncBaremetalResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBaremetalResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncBaremetalResourceWithStreamingResponse(self) + + +class BaremetalResourceWithRawResponse: + def __init__(self, baremetal: BaremetalResource) -> None: + self._baremetal = baremetal + + @cached_property + def images(self) -> ImagesResourceWithRawResponse: + return ImagesResourceWithRawResponse(self._baremetal.images) + + @cached_property + def flavors(self) -> FlavorsResourceWithRawResponse: + return FlavorsResourceWithRawResponse(self._baremetal.flavors) + + @cached_property + def servers(self) -> ServersResourceWithRawResponse: + return ServersResourceWithRawResponse(self._baremetal.servers) + + +class AsyncBaremetalResourceWithRawResponse: + def __init__(self, baremetal: AsyncBaremetalResource) -> None: + self._baremetal = baremetal + + @cached_property + def images(self) -> AsyncImagesResourceWithRawResponse: + return AsyncImagesResourceWithRawResponse(self._baremetal.images) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithRawResponse: + return AsyncFlavorsResourceWithRawResponse(self._baremetal.flavors) + + @cached_property + def servers(self) -> AsyncServersResourceWithRawResponse: + return AsyncServersResourceWithRawResponse(self._baremetal.servers) + + +class BaremetalResourceWithStreamingResponse: + def __init__(self, baremetal: BaremetalResource) -> None: + self._baremetal = baremetal + + @cached_property + def images(self) -> ImagesResourceWithStreamingResponse: + return ImagesResourceWithStreamingResponse(self._baremetal.images) + + @cached_property + def flavors(self) -> FlavorsResourceWithStreamingResponse: + return FlavorsResourceWithStreamingResponse(self._baremetal.flavors) + + @cached_property + def servers(self) -> ServersResourceWithStreamingResponse: + return ServersResourceWithStreamingResponse(self._baremetal.servers) + + +class AsyncBaremetalResourceWithStreamingResponse: + def __init__(self, baremetal: AsyncBaremetalResource) -> None: + self._baremetal = baremetal + + @cached_property + def images(self) -> AsyncImagesResourceWithStreamingResponse: + return AsyncImagesResourceWithStreamingResponse(self._baremetal.images) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithStreamingResponse: + return AsyncFlavorsResourceWithStreamingResponse(self._baremetal.flavors) + + @cached_property + def servers(self) -> AsyncServersResourceWithStreamingResponse: + return AsyncServersResourceWithStreamingResponse(self._baremetal.servers) diff --git a/src/gcore/resources/cloud/baremetal/flavors.py b/src/gcore/resources/cloud/baremetal/flavors.py new file mode 100644 index 00000000..454b0c7f --- /dev/null +++ b/src/gcore/resources/cloud/baremetal/flavors.py @@ -0,0 +1,245 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.baremetal import flavor_list_params +from ....types.cloud.baremetal_flavor_list import BaremetalFlavorList + +__all__ = ["FlavorsResource", "AsyncFlavorsResource"] + + +class FlavorsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> FlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return FlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return FlavorsResourceWithStreamingResponse(self) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + disabled: bool | Omit = omit, + exclude_linux: bool | Omit = omit, + exclude_windows: bool | Omit = omit, + include_capacity: bool | Omit = omit, + include_prices: bool | Omit = omit, + include_reservation_stock: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BaremetalFlavorList: + """List all available bare metal flavors in the specified project and region. + + When + `include_prices` is specified, the list includes pricing information. A client + in trial mode gets all price values as 0. If you get Pricing Error contact the + support. + + Args: + disabled: Flag for filtering disabled flavors in the region. Defaults to true + + exclude_linux: Set to true to exclude flavors dedicated to linux images. Default False + + exclude_windows: Set to true to exclude flavors dedicated to windows images. Default False + + include_capacity: Set to true if the response should include flavor capacity + + include_prices: Set to true if the response should include flavor prices + + include_reservation_stock: Optional. Set to true if flavor listing should include count of reserved + resources in stock. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/bmflavors/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "disabled": disabled, + "exclude_linux": exclude_linux, + "exclude_windows": exclude_windows, + "include_capacity": include_capacity, + "include_prices": include_prices, + "include_reservation_stock": include_reservation_stock, + }, + flavor_list_params.FlavorListParams, + ), + ), + cast_to=BaremetalFlavorList, + ) + + +class AsyncFlavorsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncFlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncFlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncFlavorsResourceWithStreamingResponse(self) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + disabled: bool | Omit = omit, + exclude_linux: bool | Omit = omit, + exclude_windows: bool | Omit = omit, + include_capacity: bool | Omit = omit, + include_prices: bool | Omit = omit, + include_reservation_stock: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BaremetalFlavorList: + """List all available bare metal flavors in the specified project and region. + + When + `include_prices` is specified, the list includes pricing information. A client + in trial mode gets all price values as 0. If you get Pricing Error contact the + support. + + Args: + disabled: Flag for filtering disabled flavors in the region. Defaults to true + + exclude_linux: Set to true to exclude flavors dedicated to linux images. Default False + + exclude_windows: Set to true to exclude flavors dedicated to windows images. Default False + + include_capacity: Set to true if the response should include flavor capacity + + include_prices: Set to true if the response should include flavor prices + + include_reservation_stock: Optional. Set to true if flavor listing should include count of reserved + resources in stock. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/bmflavors/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "disabled": disabled, + "exclude_linux": exclude_linux, + "exclude_windows": exclude_windows, + "include_capacity": include_capacity, + "include_prices": include_prices, + "include_reservation_stock": include_reservation_stock, + }, + flavor_list_params.FlavorListParams, + ), + ), + cast_to=BaremetalFlavorList, + ) + + +class FlavorsResourceWithRawResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_raw_response_wrapper( + flavors.list, + ) + + +class AsyncFlavorsResourceWithRawResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_raw_response_wrapper( + flavors.list, + ) + + +class FlavorsResourceWithStreamingResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_streamed_response_wrapper( + flavors.list, + ) + + +class AsyncFlavorsResourceWithStreamingResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_streamed_response_wrapper( + flavors.list, + ) diff --git a/src/gcore/resources/cloud/baremetal/images.py b/src/gcore/resources/cloud/baremetal/images.py new file mode 100644 index 00000000..16f4d22c --- /dev/null +++ b/src/gcore/resources/cloud/baremetal/images.py @@ -0,0 +1,235 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.baremetal import image_list_params +from ....types.cloud.image_list import ImageList + +__all__ = ["ImagesResource", "AsyncImagesResource"] + + +class ImagesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ImagesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ImagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ImagesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ImagesResourceWithStreamingResponse(self) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + include_prices: bool | Omit = omit, + private: str | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + visibility: Literal["private", "public", "shared"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ImageList: + """Retrieve a list of available images for bare metal servers. + + The list can be + filtered by visibility, tags, and other parameters. Returned entities may or may + not be owned by the project. + + Args: + include_prices: Show price + + private: Any value to show private images + + tag_key: Filter by tag keys. + + tag_key_value: Filter by tag key-value pairs. Must be a valid JSON string. + + visibility: Image visibility. Globally visible images are public + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/bmimages/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "include_prices": include_prices, + "private": private, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + "visibility": visibility, + }, + image_list_params.ImageListParams, + ), + ), + cast_to=ImageList, + ) + + +class AsyncImagesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncImagesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncImagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncImagesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncImagesResourceWithStreamingResponse(self) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + include_prices: bool | Omit = omit, + private: str | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + visibility: Literal["private", "public", "shared"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ImageList: + """Retrieve a list of available images for bare metal servers. + + The list can be + filtered by visibility, tags, and other parameters. Returned entities may or may + not be owned by the project. + + Args: + include_prices: Show price + + private: Any value to show private images + + tag_key: Filter by tag keys. + + tag_key_value: Filter by tag key-value pairs. Must be a valid JSON string. + + visibility: Image visibility. Globally visible images are public + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/bmimages/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "include_prices": include_prices, + "private": private, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + "visibility": visibility, + }, + image_list_params.ImageListParams, + ), + ), + cast_to=ImageList, + ) + + +class ImagesResourceWithRawResponse: + def __init__(self, images: ImagesResource) -> None: + self._images = images + + self.list = to_raw_response_wrapper( + images.list, + ) + + +class AsyncImagesResourceWithRawResponse: + def __init__(self, images: AsyncImagesResource) -> None: + self._images = images + + self.list = async_to_raw_response_wrapper( + images.list, + ) + + +class ImagesResourceWithStreamingResponse: + def __init__(self, images: ImagesResource) -> None: + self._images = images + + self.list = to_streamed_response_wrapper( + images.list, + ) + + +class AsyncImagesResourceWithStreamingResponse: + def __init__(self, images: AsyncImagesResource) -> None: + self._images = images + + self.list = async_to_streamed_response_wrapper( + images.list, + ) diff --git a/src/gcore/resources/cloud/baremetal/servers.py b/src/gcore/resources/cloud/baremetal/servers.py new file mode 100644 index 00000000..f14cb7c9 --- /dev/null +++ b/src/gcore/resources/cloud/baremetal/servers.py @@ -0,0 +1,829 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.baremetal import server_list_params, server_create_params, server_rebuild_params +from ....types.cloud.task_id_list import TaskIDList +from ....types.cloud.baremetal.baremetal_server import BaremetalServer + +__all__ = ["ServersResource", "AsyncServersResource"] + + +class ServersResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ServersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ServersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ServersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ServersResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor: str, + interfaces: Iterable[server_create_params.Interface], + app_config: Optional[Dict[str, object]] | Omit = omit, + apptemplate_id: str | Omit = omit, + ddos_profile: server_create_params.DDOSProfile | Omit = omit, + image_id: str | Omit = omit, + name: str | Omit = omit, + name_template: str | Omit = omit, + password: str | Omit = omit, + ssh_key_name: Optional[str] | Omit = omit, + tags: object | Omit = omit, + user_data: str | Omit = omit, + username: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new bare metal server with the specified configuration. + + How to get access: + + For Linux, + + - Use the `user_data` field to provide a + [cloud-init script](https://cloudinit.readthedocs.io/en/latest/reference/examples.html) + in base64 to apply configurations to the instance. + - Specify the `username` and `password` to create a new user. + - When only `password` is provided, it is set as the password for the default + user of the image. + - The `user_data` is ignored when the `password` is specified. + + For Windows, + + - Use the `user_data` field to provide a + [cloudbase-init script](https://cloudbase-init.readthedocs.io/en/latest/userdata.html#cloud-config) + in base64 to create new users on Windows. + - Use the `password` field to set the password for the 'Admin' user on Windows. + - The password of the Admin user cannot be updated via `user_data`. + - The `username` cannot be specified in the request. + + Args: + project_id: Project ID + + region_id: Region ID + + flavor: The flavor of the instance. + + interfaces: A list of network interfaces for the server. You can create one or more + interfaces - private, public, or both. + + app_config: Parameters for the application template if creating the instance from an + `apptemplate`. + + apptemplate_id: Apptemplate ID. Either `image_id` or `apptemplate_id` is required. + + ddos_profile: Enable advanced DDoS protection for the server + + image_id: Image ID. Either `image_id` or `apptemplate_id` is required. + + name: Server name. + + name_template: If you want server names to be automatically generated based on IP addresses, + you can provide a name template instead of specifying the name manually. The + template should include a placeholder that will be replaced during provisioning. + Supported placeholders are: `{ip_octets}` (last 3 octets of the IP), + `{two_ip_octets}`, and `{one_ip_octet}`. + + password: For Linux instances, 'username' and 'password' are used to create a new user. + When only 'password' is provided, it is set as the password for the default user + of the image. For Windows instances, 'username' cannot be specified. Use the + 'password' field to set the password for the 'Admin' user on Windows. Use the + 'user_data' field to provide a script to create new users on Windows. The + password of the Admin user cannot be updated via 'user_data'. + + ssh_key_name: Specifies the name of the SSH keypair, created via the + [/v1/`ssh_keys` endpoint](/docs/api-reference/cloud/ssh-keys/add-or-generate-ssh-key). + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + user_data: String in base64 format. For Linux instances, 'user_data' is ignored when + 'password' field is provided. For Windows instances, Admin user password is set + by 'password' field and cannot be updated via 'user_data'. Examples of the + `user_data`: https://cloudinit.readthedocs.io/en/latest/topics/examples.html + + username: For Linux instances, 'username' and 'password' are used to create a new user. + For Windows instances, 'username' cannot be specified. Use 'password' field to + set the password for the 'Admin' user on Windows. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/bminstances/{project_id}/{region_id}", + body=maybe_transform( + { + "flavor": flavor, + "interfaces": interfaces, + "app_config": app_config, + "apptemplate_id": apptemplate_id, + "ddos_profile": ddos_profile, + "image_id": image_id, + "name": name, + "name_template": name_template, + "password": password, + "ssh_key_name": ssh_key_name, + "tags": tags, + "user_data": user_data, + "username": username, + }, + server_create_params.ServerCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + changes_before: Union[str, datetime] | Omit = omit, + changes_since: Union[str, datetime] | Omit = omit, + flavor_id: str | Omit = omit, + flavor_prefix: str | Omit = omit, + include_k8s: bool | Omit = omit, + ip: str | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + only_isolated: bool | Omit = omit, + only_with_fixed_external_ip: bool | Omit = omit, + order_by: Literal["created.asc", "created.desc", "name.asc", "name.desc", "status.asc", "status.desc"] + | Omit = omit, + profile_name: str | Omit = omit, + protection_status: Literal["Active", "Queued", "Error"] | Omit = omit, + status: Literal[ + "ACTIVE", "BUILD", "ERROR", "HARD_REBOOT", "REBOOT", "REBUILD", "RESCUE", "SHUTOFF", "SUSPENDED" + ] + | Omit = omit, + tag_key_value: str | Omit = omit, + tag_value: SequenceNotStr[str] | Omit = omit, + type_ddos_profile: Literal["basic", "advanced"] | Omit = omit, + uuid: str | Omit = omit, + with_ddos: bool | Omit = omit, + with_interfaces_name: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[BaremetalServer]: + """List all bare metal servers in the specified project and region. + + Results can be + filtered by various parameters like name, status, and IP address. + + Args: + project_id: Project ID + + region_id: Region ID + + changes_before: Filters the instances by a date and time stamp when the instances last changed. + + changes_since: Filters the instances by a date and time stamp when the instances last changed + status. + + flavor_id: Filter out instances by `flavor_id`. Flavor id must match exactly. + + flavor_prefix: Filter out instances by `flavor_prefix`. + + include_k8s: Include managed k8s worker nodes + + ip: An IPv4 address to filter results by. Note: partial matches are allowed. For + example, searching for 192.168.0.1 will return 192.168.0.1, 192.168.0.10, + 192.168.0.110, and so on. + + limit: Optional. Limit the number of returned items + + name: Filter instances by name. You can provide a full or partial name, instances with + matching names will be returned. For example, entering 'test' will return all + instances that contain 'test' in their name. + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + only_isolated: Include only isolated instances + + only_with_fixed_external_ip: Return bare metals only with external fixed IP addresses. + + order_by: Order by field and direction. + + profile_name: Filter result by ddos protection profile name. Effective only with `with_ddos` + set to true. + + protection_status: Filter result by DDoS `protection_status`. Effective only with `with_ddos` set + to true. (Active, Queued or Error) + + status: Filters instances by a server status, as a string. + + tag_key_value: Optional. Filter by tag key-value pairs. + + tag_value: Optional. Filter by tag values. ?`tag_value`=value1&`tag_value`=value2 + + type_ddos_profile: Return bare metals either only with advanced or only basic DDoS protection. + Effective only with `with_ddos` set to true. (advanced or basic) + + uuid: Filter the server list result by the UUID of the server. Allowed UUID part + + with_ddos: Include DDoS profile information for bare-metal servers in the response when set + to `true`. Otherwise, the `ddos_profile` field in the response is `null` by + default. + + with_interfaces_name: Include `interface_name` in the addresses + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/bminstances/{project_id}/{region_id}", + page=SyncOffsetPage[BaremetalServer], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "changes_before": changes_before, + "changes_since": changes_since, + "flavor_id": flavor_id, + "flavor_prefix": flavor_prefix, + "include_k8s": include_k8s, + "ip": ip, + "limit": limit, + "name": name, + "offset": offset, + "only_isolated": only_isolated, + "only_with_fixed_external_ip": only_with_fixed_external_ip, + "order_by": order_by, + "profile_name": profile_name, + "protection_status": protection_status, + "status": status, + "tag_key_value": tag_key_value, + "tag_value": tag_value, + "type_ddos_profile": type_ddos_profile, + "uuid": uuid, + "with_ddos": with_ddos, + "with_interfaces_name": with_interfaces_name, + }, + server_list_params.ServerListParams, + ), + ), + model=BaremetalServer, + ) + + def rebuild( + self, + server_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + image_id: str | Omit = omit, + user_data: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Rebuild a bare metal server with a new image while preserving its configuration. + + Args: + project_id: Project ID + + region_id: Region ID + + server_id: Server ID + + image_id: Image ID + + user_data: String in base64 format. Must not be passed together with 'username' or + 'password'. Examples of the `user_data`: + https://cloudinit.readthedocs.io/en/latest/topics/examples.html + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not server_id: + raise ValueError(f"Expected a non-empty value for `server_id` but received {server_id!r}") + return self._post( + f"/cloud/v1/bminstances/{project_id}/{region_id}/{server_id}/rebuild", + body=maybe_transform( + { + "image_id": image_id, + "user_data": user_data, + }, + server_rebuild_params.ServerRebuildParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncServersResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncServersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncServersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncServersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncServersResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor: str, + interfaces: Iterable[server_create_params.Interface], + app_config: Optional[Dict[str, object]] | Omit = omit, + apptemplate_id: str | Omit = omit, + ddos_profile: server_create_params.DDOSProfile | Omit = omit, + image_id: str | Omit = omit, + name: str | Omit = omit, + name_template: str | Omit = omit, + password: str | Omit = omit, + ssh_key_name: Optional[str] | Omit = omit, + tags: object | Omit = omit, + user_data: str | Omit = omit, + username: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new bare metal server with the specified configuration. + + How to get access: + + For Linux, + + - Use the `user_data` field to provide a + [cloud-init script](https://cloudinit.readthedocs.io/en/latest/reference/examples.html) + in base64 to apply configurations to the instance. + - Specify the `username` and `password` to create a new user. + - When only `password` is provided, it is set as the password for the default + user of the image. + - The `user_data` is ignored when the `password` is specified. + + For Windows, + + - Use the `user_data` field to provide a + [cloudbase-init script](https://cloudbase-init.readthedocs.io/en/latest/userdata.html#cloud-config) + in base64 to create new users on Windows. + - Use the `password` field to set the password for the 'Admin' user on Windows. + - The password of the Admin user cannot be updated via `user_data`. + - The `username` cannot be specified in the request. + + Args: + project_id: Project ID + + region_id: Region ID + + flavor: The flavor of the instance. + + interfaces: A list of network interfaces for the server. You can create one or more + interfaces - private, public, or both. + + app_config: Parameters for the application template if creating the instance from an + `apptemplate`. + + apptemplate_id: Apptemplate ID. Either `image_id` or `apptemplate_id` is required. + + ddos_profile: Enable advanced DDoS protection for the server + + image_id: Image ID. Either `image_id` or `apptemplate_id` is required. + + name: Server name. + + name_template: If you want server names to be automatically generated based on IP addresses, + you can provide a name template instead of specifying the name manually. The + template should include a placeholder that will be replaced during provisioning. + Supported placeholders are: `{ip_octets}` (last 3 octets of the IP), + `{two_ip_octets}`, and `{one_ip_octet}`. + + password: For Linux instances, 'username' and 'password' are used to create a new user. + When only 'password' is provided, it is set as the password for the default user + of the image. For Windows instances, 'username' cannot be specified. Use the + 'password' field to set the password for the 'Admin' user on Windows. Use the + 'user_data' field to provide a script to create new users on Windows. The + password of the Admin user cannot be updated via 'user_data'. + + ssh_key_name: Specifies the name of the SSH keypair, created via the + [/v1/`ssh_keys` endpoint](/docs/api-reference/cloud/ssh-keys/add-or-generate-ssh-key). + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + user_data: String in base64 format. For Linux instances, 'user_data' is ignored when + 'password' field is provided. For Windows instances, Admin user password is set + by 'password' field and cannot be updated via 'user_data'. Examples of the + `user_data`: https://cloudinit.readthedocs.io/en/latest/topics/examples.html + + username: For Linux instances, 'username' and 'password' are used to create a new user. + For Windows instances, 'username' cannot be specified. Use 'password' field to + set the password for the 'Admin' user on Windows. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/bminstances/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "flavor": flavor, + "interfaces": interfaces, + "app_config": app_config, + "apptemplate_id": apptemplate_id, + "ddos_profile": ddos_profile, + "image_id": image_id, + "name": name, + "name_template": name_template, + "password": password, + "ssh_key_name": ssh_key_name, + "tags": tags, + "user_data": user_data, + "username": username, + }, + server_create_params.ServerCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + changes_before: Union[str, datetime] | Omit = omit, + changes_since: Union[str, datetime] | Omit = omit, + flavor_id: str | Omit = omit, + flavor_prefix: str | Omit = omit, + include_k8s: bool | Omit = omit, + ip: str | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + only_isolated: bool | Omit = omit, + only_with_fixed_external_ip: bool | Omit = omit, + order_by: Literal["created.asc", "created.desc", "name.asc", "name.desc", "status.asc", "status.desc"] + | Omit = omit, + profile_name: str | Omit = omit, + protection_status: Literal["Active", "Queued", "Error"] | Omit = omit, + status: Literal[ + "ACTIVE", "BUILD", "ERROR", "HARD_REBOOT", "REBOOT", "REBUILD", "RESCUE", "SHUTOFF", "SUSPENDED" + ] + | Omit = omit, + tag_key_value: str | Omit = omit, + tag_value: SequenceNotStr[str] | Omit = omit, + type_ddos_profile: Literal["basic", "advanced"] | Omit = omit, + uuid: str | Omit = omit, + with_ddos: bool | Omit = omit, + with_interfaces_name: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[BaremetalServer, AsyncOffsetPage[BaremetalServer]]: + """List all bare metal servers in the specified project and region. + + Results can be + filtered by various parameters like name, status, and IP address. + + Args: + project_id: Project ID + + region_id: Region ID + + changes_before: Filters the instances by a date and time stamp when the instances last changed. + + changes_since: Filters the instances by a date and time stamp when the instances last changed + status. + + flavor_id: Filter out instances by `flavor_id`. Flavor id must match exactly. + + flavor_prefix: Filter out instances by `flavor_prefix`. + + include_k8s: Include managed k8s worker nodes + + ip: An IPv4 address to filter results by. Note: partial matches are allowed. For + example, searching for 192.168.0.1 will return 192.168.0.1, 192.168.0.10, + 192.168.0.110, and so on. + + limit: Optional. Limit the number of returned items + + name: Filter instances by name. You can provide a full or partial name, instances with + matching names will be returned. For example, entering 'test' will return all + instances that contain 'test' in their name. + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + only_isolated: Include only isolated instances + + only_with_fixed_external_ip: Return bare metals only with external fixed IP addresses. + + order_by: Order by field and direction. + + profile_name: Filter result by ddos protection profile name. Effective only with `with_ddos` + set to true. + + protection_status: Filter result by DDoS `protection_status`. Effective only with `with_ddos` set + to true. (Active, Queued or Error) + + status: Filters instances by a server status, as a string. + + tag_key_value: Optional. Filter by tag key-value pairs. + + tag_value: Optional. Filter by tag values. ?`tag_value`=value1&`tag_value`=value2 + + type_ddos_profile: Return bare metals either only with advanced or only basic DDoS protection. + Effective only with `with_ddos` set to true. (advanced or basic) + + uuid: Filter the server list result by the UUID of the server. Allowed UUID part + + with_ddos: Include DDoS profile information for bare-metal servers in the response when set + to `true`. Otherwise, the `ddos_profile` field in the response is `null` by + default. + + with_interfaces_name: Include `interface_name` in the addresses + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/bminstances/{project_id}/{region_id}", + page=AsyncOffsetPage[BaremetalServer], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "changes_before": changes_before, + "changes_since": changes_since, + "flavor_id": flavor_id, + "flavor_prefix": flavor_prefix, + "include_k8s": include_k8s, + "ip": ip, + "limit": limit, + "name": name, + "offset": offset, + "only_isolated": only_isolated, + "only_with_fixed_external_ip": only_with_fixed_external_ip, + "order_by": order_by, + "profile_name": profile_name, + "protection_status": protection_status, + "status": status, + "tag_key_value": tag_key_value, + "tag_value": tag_value, + "type_ddos_profile": type_ddos_profile, + "uuid": uuid, + "with_ddos": with_ddos, + "with_interfaces_name": with_interfaces_name, + }, + server_list_params.ServerListParams, + ), + ), + model=BaremetalServer, + ) + + async def rebuild( + self, + server_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + image_id: str | Omit = omit, + user_data: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Rebuild a bare metal server with a new image while preserving its configuration. + + Args: + project_id: Project ID + + region_id: Region ID + + server_id: Server ID + + image_id: Image ID + + user_data: String in base64 format. Must not be passed together with 'username' or + 'password'. Examples of the `user_data`: + https://cloudinit.readthedocs.io/en/latest/topics/examples.html + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not server_id: + raise ValueError(f"Expected a non-empty value for `server_id` but received {server_id!r}") + return await self._post( + f"/cloud/v1/bminstances/{project_id}/{region_id}/{server_id}/rebuild", + body=await async_maybe_transform( + { + "image_id": image_id, + "user_data": user_data, + }, + server_rebuild_params.ServerRebuildParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class ServersResourceWithRawResponse: + def __init__(self, servers: ServersResource) -> None: + self._servers = servers + + self.create = to_raw_response_wrapper( + servers.create, + ) + self.list = to_raw_response_wrapper( + servers.list, + ) + self.rebuild = to_raw_response_wrapper( + servers.rebuild, + ) + + +class AsyncServersResourceWithRawResponse: + def __init__(self, servers: AsyncServersResource) -> None: + self._servers = servers + + self.create = async_to_raw_response_wrapper( + servers.create, + ) + self.list = async_to_raw_response_wrapper( + servers.list, + ) + self.rebuild = async_to_raw_response_wrapper( + servers.rebuild, + ) + + +class ServersResourceWithStreamingResponse: + def __init__(self, servers: ServersResource) -> None: + self._servers = servers + + self.create = to_streamed_response_wrapper( + servers.create, + ) + self.list = to_streamed_response_wrapper( + servers.list, + ) + self.rebuild = to_streamed_response_wrapper( + servers.rebuild, + ) + + +class AsyncServersResourceWithStreamingResponse: + def __init__(self, servers: AsyncServersResource) -> None: + self._servers = servers + + self.create = async_to_streamed_response_wrapper( + servers.create, + ) + self.list = async_to_streamed_response_wrapper( + servers.list, + ) + self.rebuild = async_to_streamed_response_wrapper( + servers.rebuild, + ) diff --git a/src/gcore/resources/cloud/billing_reservations.py b/src/gcore/resources/cloud/billing_reservations.py new file mode 100644 index 00000000..1ea0a26c --- /dev/null +++ b/src/gcore/resources/cloud/billing_reservations.py @@ -0,0 +1,211 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cloud import billing_reservation_list_params +from ..._base_client import make_request_options +from ...types.cloud.billing_reservations import BillingReservations + +__all__ = ["BillingReservationsResource", "AsyncBillingReservationsResource"] + + +class BillingReservationsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> BillingReservationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return BillingReservationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BillingReservationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return BillingReservationsResourceWithStreamingResponse(self) + + def list( + self, + *, + metric_name: str | Omit = omit, + order_by: Literal["active_from.asc", "active_from.desc", "active_to.asc", "active_to.desc"] | Omit = omit, + region_id: int | Omit = omit, + show_inactive: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BillingReservations: + """ + Get a list of billing reservations along with detailed information on resource + configurations and associated pricing. + + Args: + metric_name: Metric name for the resource (e.g., 'bm1-hf-medium_min') + + order_by: Order by field and direction. + + region_id: Region for reservation + + show_inactive: Include inactive commits in the response + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/cloud/v2/reservations", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "metric_name": metric_name, + "order_by": order_by, + "region_id": region_id, + "show_inactive": show_inactive, + }, + billing_reservation_list_params.BillingReservationListParams, + ), + ), + cast_to=BillingReservations, + ) + + +class AsyncBillingReservationsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncBillingReservationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncBillingReservationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBillingReservationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncBillingReservationsResourceWithStreamingResponse(self) + + async def list( + self, + *, + metric_name: str | Omit = omit, + order_by: Literal["active_from.asc", "active_from.desc", "active_to.asc", "active_to.desc"] | Omit = omit, + region_id: int | Omit = omit, + show_inactive: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BillingReservations: + """ + Get a list of billing reservations along with detailed information on resource + configurations and associated pricing. + + Args: + metric_name: Metric name for the resource (e.g., 'bm1-hf-medium_min') + + order_by: Order by field and direction. + + region_id: Region for reservation + + show_inactive: Include inactive commits in the response + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/cloud/v2/reservations", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "metric_name": metric_name, + "order_by": order_by, + "region_id": region_id, + "show_inactive": show_inactive, + }, + billing_reservation_list_params.BillingReservationListParams, + ), + ), + cast_to=BillingReservations, + ) + + +class BillingReservationsResourceWithRawResponse: + def __init__(self, billing_reservations: BillingReservationsResource) -> None: + self._billing_reservations = billing_reservations + + self.list = to_raw_response_wrapper( + billing_reservations.list, + ) + + +class AsyncBillingReservationsResourceWithRawResponse: + def __init__(self, billing_reservations: AsyncBillingReservationsResource) -> None: + self._billing_reservations = billing_reservations + + self.list = async_to_raw_response_wrapper( + billing_reservations.list, + ) + + +class BillingReservationsResourceWithStreamingResponse: + def __init__(self, billing_reservations: BillingReservationsResource) -> None: + self._billing_reservations = billing_reservations + + self.list = to_streamed_response_wrapper( + billing_reservations.list, + ) + + +class AsyncBillingReservationsResourceWithStreamingResponse: + def __init__(self, billing_reservations: AsyncBillingReservationsResource) -> None: + self._billing_reservations = billing_reservations + + self.list = async_to_streamed_response_wrapper( + billing_reservations.list, + ) diff --git a/src/gcore/resources/cloud/cloud.py b/src/gcore/resources/cloud/cloud.py new file mode 100644 index 00000000..47a7caab --- /dev/null +++ b/src/gcore/resources/cloud/cloud.py @@ -0,0 +1,1040 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .tasks import ( + TasksResource, + AsyncTasksResource, + TasksResourceWithRawResponse, + AsyncTasksResourceWithRawResponse, + TasksResourceWithStreamingResponse, + AsyncTasksResourceWithStreamingResponse, +) +from .k8s.k8s import ( + K8SResource, + AsyncK8SResource, + K8SResourceWithRawResponse, + AsyncK8SResourceWithRawResponse, + K8SResourceWithStreamingResponse, + AsyncK8SResourceWithStreamingResponse, +) +from .regions import ( + RegionsResource, + AsyncRegionsResource, + RegionsResourceWithRawResponse, + AsyncRegionsResourceWithRawResponse, + RegionsResourceWithStreamingResponse, + AsyncRegionsResourceWithStreamingResponse, +) +from .secrets import ( + SecretsResource, + AsyncSecretsResource, + SecretsResourceWithRawResponse, + AsyncSecretsResourceWithRawResponse, + SecretsResourceWithStreamingResponse, + AsyncSecretsResourceWithStreamingResponse, +) +from .volumes import ( + VolumesResource, + AsyncVolumesResource, + VolumesResourceWithRawResponse, + AsyncVolumesResourceWithRawResponse, + VolumesResourceWithStreamingResponse, + AsyncVolumesResourceWithStreamingResponse, +) +from .projects import ( + ProjectsResource, + AsyncProjectsResource, + ProjectsResourceWithRawResponse, + AsyncProjectsResourceWithRawResponse, + ProjectsResourceWithStreamingResponse, + AsyncProjectsResourceWithStreamingResponse, +) +from .ssh_keys import ( + SSHKeysResource, + AsyncSSHKeysResource, + SSHKeysResourceWithRawResponse, + AsyncSSHKeysResourceWithRawResponse, + SSHKeysResourceWithStreamingResponse, + AsyncSSHKeysResourceWithStreamingResponse, +) +from ..._compat import cached_property +from .ip_ranges import ( + IPRangesResource, + AsyncIPRangesResource, + IPRangesResourceWithRawResponse, + AsyncIPRangesResourceWithRawResponse, + IPRangesResourceWithStreamingResponse, + AsyncIPRangesResourceWithStreamingResponse, +) +from .audit_logs import ( + AuditLogsResource, + AsyncAuditLogsResource, + AuditLogsResourceWithRawResponse, + AsyncAuditLogsResourceWithRawResponse, + AuditLogsResourceWithStreamingResponse, + AsyncAuditLogsResourceWithStreamingResponse, +) +from ..._resource import SyncAPIResource, AsyncAPIResource +from .users.users import ( + UsersResource, + AsyncUsersResource, + UsersResourceWithRawResponse, + AsyncUsersResourceWithRawResponse, + UsersResourceWithStreamingResponse, + AsyncUsersResourceWithStreamingResponse, +) +from .cost_reports import ( + CostReportsResource, + AsyncCostReportsResource, + CostReportsResourceWithRawResponse, + AsyncCostReportsResourceWithRawResponse, + CostReportsResourceWithStreamingResponse, + AsyncCostReportsResourceWithStreamingResponse, +) +from .floating_ips import ( + FloatingIPsResource, + AsyncFloatingIPsResource, + FloatingIPsResourceWithRawResponse, + AsyncFloatingIPsResourceWithRawResponse, + FloatingIPsResourceWithStreamingResponse, + AsyncFloatingIPsResourceWithStreamingResponse, +) +from .quotas.quotas import ( + QuotasResource, + AsyncQuotasResource, + QuotasResourceWithRawResponse, + AsyncQuotasResourceWithRawResponse, + QuotasResourceWithStreamingResponse, + AsyncQuotasResourceWithStreamingResponse, +) +from .usage_reports import ( + UsageReportsResource, + AsyncUsageReportsResource, + UsageReportsResourceWithRawResponse, + AsyncUsageReportsResourceWithRawResponse, + UsageReportsResourceWithStreamingResponse, + AsyncUsageReportsResourceWithStreamingResponse, +) +from .placement_groups import ( + PlacementGroupsResource, + AsyncPlacementGroupsResource, + PlacementGroupsResourceWithRawResponse, + AsyncPlacementGroupsResourceWithRawResponse, + PlacementGroupsResourceWithStreamingResponse, + AsyncPlacementGroupsResourceWithStreamingResponse, +) +from .volume_snapshots import ( + VolumeSnapshotsResource, + AsyncVolumeSnapshotsResource, + VolumeSnapshotsResourceWithRawResponse, + AsyncVolumeSnapshotsResourceWithRawResponse, + VolumeSnapshotsResourceWithStreamingResponse, + AsyncVolumeSnapshotsResourceWithStreamingResponse, +) +from .networks.networks import ( + NetworksResource, + AsyncNetworksResource, + NetworksResourceWithRawResponse, + AsyncNetworksResourceWithRawResponse, + NetworksResourceWithStreamingResponse, + AsyncNetworksResourceWithStreamingResponse, +) +from .baremetal.baremetal import ( + BaremetalResource, + AsyncBaremetalResource, + BaremetalResourceWithRawResponse, + AsyncBaremetalResourceWithRawResponse, + BaremetalResourceWithStreamingResponse, + AsyncBaremetalResourceWithStreamingResponse, +) +from .databases.databases import ( + DatabasesResource, + AsyncDatabasesResource, + DatabasesResourceWithRawResponse, + AsyncDatabasesResourceWithRawResponse, + DatabasesResourceWithStreamingResponse, + AsyncDatabasesResourceWithStreamingResponse, +) +from .inference.inference import ( + InferenceResource, + AsyncInferenceResource, + InferenceResourceWithRawResponse, + AsyncInferenceResourceWithRawResponse, + InferenceResourceWithStreamingResponse, + AsyncInferenceResourceWithStreamingResponse, +) +from .instances.instances import ( + InstancesResource, + AsyncInstancesResource, + InstancesResourceWithRawResponse, + AsyncInstancesResourceWithRawResponse, + InstancesResourceWithStreamingResponse, + AsyncInstancesResourceWithStreamingResponse, +) +from .billing_reservations import ( + BillingReservationsResource, + AsyncBillingReservationsResource, + BillingReservationsResourceWithRawResponse, + AsyncBillingReservationsResourceWithRawResponse, + BillingReservationsResourceWithStreamingResponse, + AsyncBillingReservationsResourceWithStreamingResponse, +) +from .registries.registries import ( + RegistriesResource, + AsyncRegistriesResource, + RegistriesResourceWithRawResponse, + AsyncRegistriesResourceWithRawResponse, + RegistriesResourceWithStreamingResponse, + AsyncRegistriesResourceWithStreamingResponse, +) +from .file_shares.file_shares import ( + FileSharesResource, + AsyncFileSharesResource, + FileSharesResourceWithRawResponse, + AsyncFileSharesResourceWithRawResponse, + FileSharesResourceWithStreamingResponse, + AsyncFileSharesResourceWithStreamingResponse, +) +from .gpu_virtual.gpu_virtual import ( + GPUVirtualResource, + AsyncGPUVirtualResource, + GPUVirtualResourceWithRawResponse, + AsyncGPUVirtualResourceWithRawResponse, + GPUVirtualResourceWithStreamingResponse, + AsyncGPUVirtualResourceWithStreamingResponse, +) +from .gpu_baremetal.gpu_baremetal import ( + GPUBaremetalResource, + AsyncGPUBaremetalResource, + GPUBaremetalResourceWithRawResponse, + AsyncGPUBaremetalResourceWithRawResponse, + GPUBaremetalResourceWithStreamingResponse, + AsyncGPUBaremetalResourceWithStreamingResponse, +) +from .load_balancers.load_balancers import ( + LoadBalancersResource, + AsyncLoadBalancersResource, + LoadBalancersResourceWithRawResponse, + AsyncLoadBalancersResourceWithRawResponse, + LoadBalancersResourceWithStreamingResponse, + AsyncLoadBalancersResourceWithStreamingResponse, +) +from .security_groups.security_groups import ( + SecurityGroupsResource, + AsyncSecurityGroupsResource, + SecurityGroupsResourceWithRawResponse, + AsyncSecurityGroupsResourceWithRawResponse, + SecurityGroupsResourceWithStreamingResponse, + AsyncSecurityGroupsResourceWithStreamingResponse, +) +from .reserved_fixed_ips.reserved_fixed_ips import ( + ReservedFixedIPsResource, + AsyncReservedFixedIPsResource, + ReservedFixedIPsResourceWithRawResponse, + AsyncReservedFixedIPsResourceWithRawResponse, + ReservedFixedIPsResourceWithStreamingResponse, + AsyncReservedFixedIPsResourceWithStreamingResponse, +) + +__all__ = ["CloudResource", "AsyncCloudResource"] + + +class CloudResource(SyncAPIResource): + @cached_property + def projects(self) -> ProjectsResource: + return ProjectsResource(self._client) + + @cached_property + def tasks(self) -> TasksResource: + return TasksResource(self._client) + + @cached_property + def regions(self) -> RegionsResource: + return RegionsResource(self._client) + + @cached_property + def quotas(self) -> QuotasResource: + return QuotasResource(self._client) + + @cached_property + def secrets(self) -> SecretsResource: + return SecretsResource(self._client) + + @cached_property + def ssh_keys(self) -> SSHKeysResource: + return SSHKeysResource(self._client) + + @cached_property + def ip_ranges(self) -> IPRangesResource: + return IPRangesResource(self._client) + + @cached_property + def load_balancers(self) -> LoadBalancersResource: + return LoadBalancersResource(self._client) + + @cached_property + def reserved_fixed_ips(self) -> ReservedFixedIPsResource: + return ReservedFixedIPsResource(self._client) + + @cached_property + def networks(self) -> NetworksResource: + return NetworksResource(self._client) + + @cached_property + def volumes(self) -> VolumesResource: + return VolumesResource(self._client) + + @cached_property + def floating_ips(self) -> FloatingIPsResource: + """A floating IP is a static IP address that points to one of your Instances. + + It allows you to redirect network traffic to any of your Instances in the same datacenter. + """ + return FloatingIPsResource(self._client) + + @cached_property + def security_groups(self) -> SecurityGroupsResource: + return SecurityGroupsResource(self._client) + + @cached_property + def users(self) -> UsersResource: + return UsersResource(self._client) + + @cached_property + def inference(self) -> InferenceResource: + return InferenceResource(self._client) + + @cached_property + def placement_groups(self) -> PlacementGroupsResource: + """ + Placement Groups allow you to specific a policy that determines whether Virtual Machines will be hosted on the same physical server or on different ones. + """ + return PlacementGroupsResource(self._client) + + @cached_property + def baremetal(self) -> BaremetalResource: + return BaremetalResource(self._client) + + @cached_property + def registries(self) -> RegistriesResource: + return RegistriesResource(self._client) + + @cached_property + def file_shares(self) -> FileSharesResource: + return FileSharesResource(self._client) + + @cached_property + def billing_reservations(self) -> BillingReservationsResource: + return BillingReservationsResource(self._client) + + @cached_property + def gpu_baremetal(self) -> GPUBaremetalResource: + return GPUBaremetalResource(self._client) + + @cached_property + def gpu_virtual(self) -> GPUVirtualResource: + return GPUVirtualResource(self._client) + + @cached_property + def instances(self) -> InstancesResource: + return InstancesResource(self._client) + + @cached_property + def k8s(self) -> K8SResource: + return K8SResource(self._client) + + @cached_property + def audit_logs(self) -> AuditLogsResource: + return AuditLogsResource(self._client) + + @cached_property + def cost_reports(self) -> CostReportsResource: + return CostReportsResource(self._client) + + @cached_property + def usage_reports(self) -> UsageReportsResource: + return UsageReportsResource(self._client) + + @cached_property + def databases(self) -> DatabasesResource: + return DatabasesResource(self._client) + + @cached_property + def volume_snapshots(self) -> VolumeSnapshotsResource: + return VolumeSnapshotsResource(self._client) + + @cached_property + def with_raw_response(self) -> CloudResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return CloudResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CloudResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return CloudResourceWithStreamingResponse(self) + + +class AsyncCloudResource(AsyncAPIResource): + @cached_property + def projects(self) -> AsyncProjectsResource: + return AsyncProjectsResource(self._client) + + @cached_property + def tasks(self) -> AsyncTasksResource: + return AsyncTasksResource(self._client) + + @cached_property + def regions(self) -> AsyncRegionsResource: + return AsyncRegionsResource(self._client) + + @cached_property + def quotas(self) -> AsyncQuotasResource: + return AsyncQuotasResource(self._client) + + @cached_property + def secrets(self) -> AsyncSecretsResource: + return AsyncSecretsResource(self._client) + + @cached_property + def ssh_keys(self) -> AsyncSSHKeysResource: + return AsyncSSHKeysResource(self._client) + + @cached_property + def ip_ranges(self) -> AsyncIPRangesResource: + return AsyncIPRangesResource(self._client) + + @cached_property + def load_balancers(self) -> AsyncLoadBalancersResource: + return AsyncLoadBalancersResource(self._client) + + @cached_property + def reserved_fixed_ips(self) -> AsyncReservedFixedIPsResource: + return AsyncReservedFixedIPsResource(self._client) + + @cached_property + def networks(self) -> AsyncNetworksResource: + return AsyncNetworksResource(self._client) + + @cached_property + def volumes(self) -> AsyncVolumesResource: + return AsyncVolumesResource(self._client) + + @cached_property + def floating_ips(self) -> AsyncFloatingIPsResource: + """A floating IP is a static IP address that points to one of your Instances. + + It allows you to redirect network traffic to any of your Instances in the same datacenter. + """ + return AsyncFloatingIPsResource(self._client) + + @cached_property + def security_groups(self) -> AsyncSecurityGroupsResource: + return AsyncSecurityGroupsResource(self._client) + + @cached_property + def users(self) -> AsyncUsersResource: + return AsyncUsersResource(self._client) + + @cached_property + def inference(self) -> AsyncInferenceResource: + return AsyncInferenceResource(self._client) + + @cached_property + def placement_groups(self) -> AsyncPlacementGroupsResource: + """ + Placement Groups allow you to specific a policy that determines whether Virtual Machines will be hosted on the same physical server or on different ones. + """ + return AsyncPlacementGroupsResource(self._client) + + @cached_property + def baremetal(self) -> AsyncBaremetalResource: + return AsyncBaremetalResource(self._client) + + @cached_property + def registries(self) -> AsyncRegistriesResource: + return AsyncRegistriesResource(self._client) + + @cached_property + def file_shares(self) -> AsyncFileSharesResource: + return AsyncFileSharesResource(self._client) + + @cached_property + def billing_reservations(self) -> AsyncBillingReservationsResource: + return AsyncBillingReservationsResource(self._client) + + @cached_property + def gpu_baremetal(self) -> AsyncGPUBaremetalResource: + return AsyncGPUBaremetalResource(self._client) + + @cached_property + def gpu_virtual(self) -> AsyncGPUVirtualResource: + return AsyncGPUVirtualResource(self._client) + + @cached_property + def instances(self) -> AsyncInstancesResource: + return AsyncInstancesResource(self._client) + + @cached_property + def k8s(self) -> AsyncK8SResource: + return AsyncK8SResource(self._client) + + @cached_property + def audit_logs(self) -> AsyncAuditLogsResource: + return AsyncAuditLogsResource(self._client) + + @cached_property + def cost_reports(self) -> AsyncCostReportsResource: + return AsyncCostReportsResource(self._client) + + @cached_property + def usage_reports(self) -> AsyncUsageReportsResource: + return AsyncUsageReportsResource(self._client) + + @cached_property + def databases(self) -> AsyncDatabasesResource: + return AsyncDatabasesResource(self._client) + + @cached_property + def volume_snapshots(self) -> AsyncVolumeSnapshotsResource: + return AsyncVolumeSnapshotsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncCloudResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncCloudResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCloudResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncCloudResourceWithStreamingResponse(self) + + +class CloudResourceWithRawResponse: + def __init__(self, cloud: CloudResource) -> None: + self._cloud = cloud + + @cached_property + def projects(self) -> ProjectsResourceWithRawResponse: + return ProjectsResourceWithRawResponse(self._cloud.projects) + + @cached_property + def tasks(self) -> TasksResourceWithRawResponse: + return TasksResourceWithRawResponse(self._cloud.tasks) + + @cached_property + def regions(self) -> RegionsResourceWithRawResponse: + return RegionsResourceWithRawResponse(self._cloud.regions) + + @cached_property + def quotas(self) -> QuotasResourceWithRawResponse: + return QuotasResourceWithRawResponse(self._cloud.quotas) + + @cached_property + def secrets(self) -> SecretsResourceWithRawResponse: + return SecretsResourceWithRawResponse(self._cloud.secrets) + + @cached_property + def ssh_keys(self) -> SSHKeysResourceWithRawResponse: + return SSHKeysResourceWithRawResponse(self._cloud.ssh_keys) + + @cached_property + def ip_ranges(self) -> IPRangesResourceWithRawResponse: + return IPRangesResourceWithRawResponse(self._cloud.ip_ranges) + + @cached_property + def load_balancers(self) -> LoadBalancersResourceWithRawResponse: + return LoadBalancersResourceWithRawResponse(self._cloud.load_balancers) + + @cached_property + def reserved_fixed_ips(self) -> ReservedFixedIPsResourceWithRawResponse: + return ReservedFixedIPsResourceWithRawResponse(self._cloud.reserved_fixed_ips) + + @cached_property + def networks(self) -> NetworksResourceWithRawResponse: + return NetworksResourceWithRawResponse(self._cloud.networks) + + @cached_property + def volumes(self) -> VolumesResourceWithRawResponse: + return VolumesResourceWithRawResponse(self._cloud.volumes) + + @cached_property + def floating_ips(self) -> FloatingIPsResourceWithRawResponse: + """A floating IP is a static IP address that points to one of your Instances. + + It allows you to redirect network traffic to any of your Instances in the same datacenter. + """ + return FloatingIPsResourceWithRawResponse(self._cloud.floating_ips) + + @cached_property + def security_groups(self) -> SecurityGroupsResourceWithRawResponse: + return SecurityGroupsResourceWithRawResponse(self._cloud.security_groups) + + @cached_property + def users(self) -> UsersResourceWithRawResponse: + return UsersResourceWithRawResponse(self._cloud.users) + + @cached_property + def inference(self) -> InferenceResourceWithRawResponse: + return InferenceResourceWithRawResponse(self._cloud.inference) + + @cached_property + def placement_groups(self) -> PlacementGroupsResourceWithRawResponse: + """ + Placement Groups allow you to specific a policy that determines whether Virtual Machines will be hosted on the same physical server or on different ones. + """ + return PlacementGroupsResourceWithRawResponse(self._cloud.placement_groups) + + @cached_property + def baremetal(self) -> BaremetalResourceWithRawResponse: + return BaremetalResourceWithRawResponse(self._cloud.baremetal) + + @cached_property + def registries(self) -> RegistriesResourceWithRawResponse: + return RegistriesResourceWithRawResponse(self._cloud.registries) + + @cached_property + def file_shares(self) -> FileSharesResourceWithRawResponse: + return FileSharesResourceWithRawResponse(self._cloud.file_shares) + + @cached_property + def billing_reservations(self) -> BillingReservationsResourceWithRawResponse: + return BillingReservationsResourceWithRawResponse(self._cloud.billing_reservations) + + @cached_property + def gpu_baremetal(self) -> GPUBaremetalResourceWithRawResponse: + return GPUBaremetalResourceWithRawResponse(self._cloud.gpu_baremetal) + + @cached_property + def gpu_virtual(self) -> GPUVirtualResourceWithRawResponse: + return GPUVirtualResourceWithRawResponse(self._cloud.gpu_virtual) + + @cached_property + def instances(self) -> InstancesResourceWithRawResponse: + return InstancesResourceWithRawResponse(self._cloud.instances) + + @cached_property + def k8s(self) -> K8SResourceWithRawResponse: + return K8SResourceWithRawResponse(self._cloud.k8s) + + @cached_property + def audit_logs(self) -> AuditLogsResourceWithRawResponse: + return AuditLogsResourceWithRawResponse(self._cloud.audit_logs) + + @cached_property + def cost_reports(self) -> CostReportsResourceWithRawResponse: + return CostReportsResourceWithRawResponse(self._cloud.cost_reports) + + @cached_property + def usage_reports(self) -> UsageReportsResourceWithRawResponse: + return UsageReportsResourceWithRawResponse(self._cloud.usage_reports) + + @cached_property + def databases(self) -> DatabasesResourceWithRawResponse: + return DatabasesResourceWithRawResponse(self._cloud.databases) + + @cached_property + def volume_snapshots(self) -> VolumeSnapshotsResourceWithRawResponse: + return VolumeSnapshotsResourceWithRawResponse(self._cloud.volume_snapshots) + + +class AsyncCloudResourceWithRawResponse: + def __init__(self, cloud: AsyncCloudResource) -> None: + self._cloud = cloud + + @cached_property + def projects(self) -> AsyncProjectsResourceWithRawResponse: + return AsyncProjectsResourceWithRawResponse(self._cloud.projects) + + @cached_property + def tasks(self) -> AsyncTasksResourceWithRawResponse: + return AsyncTasksResourceWithRawResponse(self._cloud.tasks) + + @cached_property + def regions(self) -> AsyncRegionsResourceWithRawResponse: + return AsyncRegionsResourceWithRawResponse(self._cloud.regions) + + @cached_property + def quotas(self) -> AsyncQuotasResourceWithRawResponse: + return AsyncQuotasResourceWithRawResponse(self._cloud.quotas) + + @cached_property + def secrets(self) -> AsyncSecretsResourceWithRawResponse: + return AsyncSecretsResourceWithRawResponse(self._cloud.secrets) + + @cached_property + def ssh_keys(self) -> AsyncSSHKeysResourceWithRawResponse: + return AsyncSSHKeysResourceWithRawResponse(self._cloud.ssh_keys) + + @cached_property + def ip_ranges(self) -> AsyncIPRangesResourceWithRawResponse: + return AsyncIPRangesResourceWithRawResponse(self._cloud.ip_ranges) + + @cached_property + def load_balancers(self) -> AsyncLoadBalancersResourceWithRawResponse: + return AsyncLoadBalancersResourceWithRawResponse(self._cloud.load_balancers) + + @cached_property + def reserved_fixed_ips(self) -> AsyncReservedFixedIPsResourceWithRawResponse: + return AsyncReservedFixedIPsResourceWithRawResponse(self._cloud.reserved_fixed_ips) + + @cached_property + def networks(self) -> AsyncNetworksResourceWithRawResponse: + return AsyncNetworksResourceWithRawResponse(self._cloud.networks) + + @cached_property + def volumes(self) -> AsyncVolumesResourceWithRawResponse: + return AsyncVolumesResourceWithRawResponse(self._cloud.volumes) + + @cached_property + def floating_ips(self) -> AsyncFloatingIPsResourceWithRawResponse: + """A floating IP is a static IP address that points to one of your Instances. + + It allows you to redirect network traffic to any of your Instances in the same datacenter. + """ + return AsyncFloatingIPsResourceWithRawResponse(self._cloud.floating_ips) + + @cached_property + def security_groups(self) -> AsyncSecurityGroupsResourceWithRawResponse: + return AsyncSecurityGroupsResourceWithRawResponse(self._cloud.security_groups) + + @cached_property + def users(self) -> AsyncUsersResourceWithRawResponse: + return AsyncUsersResourceWithRawResponse(self._cloud.users) + + @cached_property + def inference(self) -> AsyncInferenceResourceWithRawResponse: + return AsyncInferenceResourceWithRawResponse(self._cloud.inference) + + @cached_property + def placement_groups(self) -> AsyncPlacementGroupsResourceWithRawResponse: + """ + Placement Groups allow you to specific a policy that determines whether Virtual Machines will be hosted on the same physical server or on different ones. + """ + return AsyncPlacementGroupsResourceWithRawResponse(self._cloud.placement_groups) + + @cached_property + def baremetal(self) -> AsyncBaremetalResourceWithRawResponse: + return AsyncBaremetalResourceWithRawResponse(self._cloud.baremetal) + + @cached_property + def registries(self) -> AsyncRegistriesResourceWithRawResponse: + return AsyncRegistriesResourceWithRawResponse(self._cloud.registries) + + @cached_property + def file_shares(self) -> AsyncFileSharesResourceWithRawResponse: + return AsyncFileSharesResourceWithRawResponse(self._cloud.file_shares) + + @cached_property + def billing_reservations(self) -> AsyncBillingReservationsResourceWithRawResponse: + return AsyncBillingReservationsResourceWithRawResponse(self._cloud.billing_reservations) + + @cached_property + def gpu_baremetal(self) -> AsyncGPUBaremetalResourceWithRawResponse: + return AsyncGPUBaremetalResourceWithRawResponse(self._cloud.gpu_baremetal) + + @cached_property + def gpu_virtual(self) -> AsyncGPUVirtualResourceWithRawResponse: + return AsyncGPUVirtualResourceWithRawResponse(self._cloud.gpu_virtual) + + @cached_property + def instances(self) -> AsyncInstancesResourceWithRawResponse: + return AsyncInstancesResourceWithRawResponse(self._cloud.instances) + + @cached_property + def k8s(self) -> AsyncK8SResourceWithRawResponse: + return AsyncK8SResourceWithRawResponse(self._cloud.k8s) + + @cached_property + def audit_logs(self) -> AsyncAuditLogsResourceWithRawResponse: + return AsyncAuditLogsResourceWithRawResponse(self._cloud.audit_logs) + + @cached_property + def cost_reports(self) -> AsyncCostReportsResourceWithRawResponse: + return AsyncCostReportsResourceWithRawResponse(self._cloud.cost_reports) + + @cached_property + def usage_reports(self) -> AsyncUsageReportsResourceWithRawResponse: + return AsyncUsageReportsResourceWithRawResponse(self._cloud.usage_reports) + + @cached_property + def databases(self) -> AsyncDatabasesResourceWithRawResponse: + return AsyncDatabasesResourceWithRawResponse(self._cloud.databases) + + @cached_property + def volume_snapshots(self) -> AsyncVolumeSnapshotsResourceWithRawResponse: + return AsyncVolumeSnapshotsResourceWithRawResponse(self._cloud.volume_snapshots) + + +class CloudResourceWithStreamingResponse: + def __init__(self, cloud: CloudResource) -> None: + self._cloud = cloud + + @cached_property + def projects(self) -> ProjectsResourceWithStreamingResponse: + return ProjectsResourceWithStreamingResponse(self._cloud.projects) + + @cached_property + def tasks(self) -> TasksResourceWithStreamingResponse: + return TasksResourceWithStreamingResponse(self._cloud.tasks) + + @cached_property + def regions(self) -> RegionsResourceWithStreamingResponse: + return RegionsResourceWithStreamingResponse(self._cloud.regions) + + @cached_property + def quotas(self) -> QuotasResourceWithStreamingResponse: + return QuotasResourceWithStreamingResponse(self._cloud.quotas) + + @cached_property + def secrets(self) -> SecretsResourceWithStreamingResponse: + return SecretsResourceWithStreamingResponse(self._cloud.secrets) + + @cached_property + def ssh_keys(self) -> SSHKeysResourceWithStreamingResponse: + return SSHKeysResourceWithStreamingResponse(self._cloud.ssh_keys) + + @cached_property + def ip_ranges(self) -> IPRangesResourceWithStreamingResponse: + return IPRangesResourceWithStreamingResponse(self._cloud.ip_ranges) + + @cached_property + def load_balancers(self) -> LoadBalancersResourceWithStreamingResponse: + return LoadBalancersResourceWithStreamingResponse(self._cloud.load_balancers) + + @cached_property + def reserved_fixed_ips(self) -> ReservedFixedIPsResourceWithStreamingResponse: + return ReservedFixedIPsResourceWithStreamingResponse(self._cloud.reserved_fixed_ips) + + @cached_property + def networks(self) -> NetworksResourceWithStreamingResponse: + return NetworksResourceWithStreamingResponse(self._cloud.networks) + + @cached_property + def volumes(self) -> VolumesResourceWithStreamingResponse: + return VolumesResourceWithStreamingResponse(self._cloud.volumes) + + @cached_property + def floating_ips(self) -> FloatingIPsResourceWithStreamingResponse: + """A floating IP is a static IP address that points to one of your Instances. + + It allows you to redirect network traffic to any of your Instances in the same datacenter. + """ + return FloatingIPsResourceWithStreamingResponse(self._cloud.floating_ips) + + @cached_property + def security_groups(self) -> SecurityGroupsResourceWithStreamingResponse: + return SecurityGroupsResourceWithStreamingResponse(self._cloud.security_groups) + + @cached_property + def users(self) -> UsersResourceWithStreamingResponse: + return UsersResourceWithStreamingResponse(self._cloud.users) + + @cached_property + def inference(self) -> InferenceResourceWithStreamingResponse: + return InferenceResourceWithStreamingResponse(self._cloud.inference) + + @cached_property + def placement_groups(self) -> PlacementGroupsResourceWithStreamingResponse: + """ + Placement Groups allow you to specific a policy that determines whether Virtual Machines will be hosted on the same physical server or on different ones. + """ + return PlacementGroupsResourceWithStreamingResponse(self._cloud.placement_groups) + + @cached_property + def baremetal(self) -> BaremetalResourceWithStreamingResponse: + return BaremetalResourceWithStreamingResponse(self._cloud.baremetal) + + @cached_property + def registries(self) -> RegistriesResourceWithStreamingResponse: + return RegistriesResourceWithStreamingResponse(self._cloud.registries) + + @cached_property + def file_shares(self) -> FileSharesResourceWithStreamingResponse: + return FileSharesResourceWithStreamingResponse(self._cloud.file_shares) + + @cached_property + def billing_reservations(self) -> BillingReservationsResourceWithStreamingResponse: + return BillingReservationsResourceWithStreamingResponse(self._cloud.billing_reservations) + + @cached_property + def gpu_baremetal(self) -> GPUBaremetalResourceWithStreamingResponse: + return GPUBaremetalResourceWithStreamingResponse(self._cloud.gpu_baremetal) + + @cached_property + def gpu_virtual(self) -> GPUVirtualResourceWithStreamingResponse: + return GPUVirtualResourceWithStreamingResponse(self._cloud.gpu_virtual) + + @cached_property + def instances(self) -> InstancesResourceWithStreamingResponse: + return InstancesResourceWithStreamingResponse(self._cloud.instances) + + @cached_property + def k8s(self) -> K8SResourceWithStreamingResponse: + return K8SResourceWithStreamingResponse(self._cloud.k8s) + + @cached_property + def audit_logs(self) -> AuditLogsResourceWithStreamingResponse: + return AuditLogsResourceWithStreamingResponse(self._cloud.audit_logs) + + @cached_property + def cost_reports(self) -> CostReportsResourceWithStreamingResponse: + return CostReportsResourceWithStreamingResponse(self._cloud.cost_reports) + + @cached_property + def usage_reports(self) -> UsageReportsResourceWithStreamingResponse: + return UsageReportsResourceWithStreamingResponse(self._cloud.usage_reports) + + @cached_property + def databases(self) -> DatabasesResourceWithStreamingResponse: + return DatabasesResourceWithStreamingResponse(self._cloud.databases) + + @cached_property + def volume_snapshots(self) -> VolumeSnapshotsResourceWithStreamingResponse: + return VolumeSnapshotsResourceWithStreamingResponse(self._cloud.volume_snapshots) + + +class AsyncCloudResourceWithStreamingResponse: + def __init__(self, cloud: AsyncCloudResource) -> None: + self._cloud = cloud + + @cached_property + def projects(self) -> AsyncProjectsResourceWithStreamingResponse: + return AsyncProjectsResourceWithStreamingResponse(self._cloud.projects) + + @cached_property + def tasks(self) -> AsyncTasksResourceWithStreamingResponse: + return AsyncTasksResourceWithStreamingResponse(self._cloud.tasks) + + @cached_property + def regions(self) -> AsyncRegionsResourceWithStreamingResponse: + return AsyncRegionsResourceWithStreamingResponse(self._cloud.regions) + + @cached_property + def quotas(self) -> AsyncQuotasResourceWithStreamingResponse: + return AsyncQuotasResourceWithStreamingResponse(self._cloud.quotas) + + @cached_property + def secrets(self) -> AsyncSecretsResourceWithStreamingResponse: + return AsyncSecretsResourceWithStreamingResponse(self._cloud.secrets) + + @cached_property + def ssh_keys(self) -> AsyncSSHKeysResourceWithStreamingResponse: + return AsyncSSHKeysResourceWithStreamingResponse(self._cloud.ssh_keys) + + @cached_property + def ip_ranges(self) -> AsyncIPRangesResourceWithStreamingResponse: + return AsyncIPRangesResourceWithStreamingResponse(self._cloud.ip_ranges) + + @cached_property + def load_balancers(self) -> AsyncLoadBalancersResourceWithStreamingResponse: + return AsyncLoadBalancersResourceWithStreamingResponse(self._cloud.load_balancers) + + @cached_property + def reserved_fixed_ips(self) -> AsyncReservedFixedIPsResourceWithStreamingResponse: + return AsyncReservedFixedIPsResourceWithStreamingResponse(self._cloud.reserved_fixed_ips) + + @cached_property + def networks(self) -> AsyncNetworksResourceWithStreamingResponse: + return AsyncNetworksResourceWithStreamingResponse(self._cloud.networks) + + @cached_property + def volumes(self) -> AsyncVolumesResourceWithStreamingResponse: + return AsyncVolumesResourceWithStreamingResponse(self._cloud.volumes) + + @cached_property + def floating_ips(self) -> AsyncFloatingIPsResourceWithStreamingResponse: + """A floating IP is a static IP address that points to one of your Instances. + + It allows you to redirect network traffic to any of your Instances in the same datacenter. + """ + return AsyncFloatingIPsResourceWithStreamingResponse(self._cloud.floating_ips) + + @cached_property + def security_groups(self) -> AsyncSecurityGroupsResourceWithStreamingResponse: + return AsyncSecurityGroupsResourceWithStreamingResponse(self._cloud.security_groups) + + @cached_property + def users(self) -> AsyncUsersResourceWithStreamingResponse: + return AsyncUsersResourceWithStreamingResponse(self._cloud.users) + + @cached_property + def inference(self) -> AsyncInferenceResourceWithStreamingResponse: + return AsyncInferenceResourceWithStreamingResponse(self._cloud.inference) + + @cached_property + def placement_groups(self) -> AsyncPlacementGroupsResourceWithStreamingResponse: + """ + Placement Groups allow you to specific a policy that determines whether Virtual Machines will be hosted on the same physical server or on different ones. + """ + return AsyncPlacementGroupsResourceWithStreamingResponse(self._cloud.placement_groups) + + @cached_property + def baremetal(self) -> AsyncBaremetalResourceWithStreamingResponse: + return AsyncBaremetalResourceWithStreamingResponse(self._cloud.baremetal) + + @cached_property + def registries(self) -> AsyncRegistriesResourceWithStreamingResponse: + return AsyncRegistriesResourceWithStreamingResponse(self._cloud.registries) + + @cached_property + def file_shares(self) -> AsyncFileSharesResourceWithStreamingResponse: + return AsyncFileSharesResourceWithStreamingResponse(self._cloud.file_shares) + + @cached_property + def billing_reservations(self) -> AsyncBillingReservationsResourceWithStreamingResponse: + return AsyncBillingReservationsResourceWithStreamingResponse(self._cloud.billing_reservations) + + @cached_property + def gpu_baremetal(self) -> AsyncGPUBaremetalResourceWithStreamingResponse: + return AsyncGPUBaremetalResourceWithStreamingResponse(self._cloud.gpu_baremetal) + + @cached_property + def gpu_virtual(self) -> AsyncGPUVirtualResourceWithStreamingResponse: + return AsyncGPUVirtualResourceWithStreamingResponse(self._cloud.gpu_virtual) + + @cached_property + def instances(self) -> AsyncInstancesResourceWithStreamingResponse: + return AsyncInstancesResourceWithStreamingResponse(self._cloud.instances) + + @cached_property + def k8s(self) -> AsyncK8SResourceWithStreamingResponse: + return AsyncK8SResourceWithStreamingResponse(self._cloud.k8s) + + @cached_property + def audit_logs(self) -> AsyncAuditLogsResourceWithStreamingResponse: + return AsyncAuditLogsResourceWithStreamingResponse(self._cloud.audit_logs) + + @cached_property + def cost_reports(self) -> AsyncCostReportsResourceWithStreamingResponse: + return AsyncCostReportsResourceWithStreamingResponse(self._cloud.cost_reports) + + @cached_property + def usage_reports(self) -> AsyncUsageReportsResourceWithStreamingResponse: + return AsyncUsageReportsResourceWithStreamingResponse(self._cloud.usage_reports) + + @cached_property + def databases(self) -> AsyncDatabasesResourceWithStreamingResponse: + return AsyncDatabasesResourceWithStreamingResponse(self._cloud.databases) + + @cached_property + def volume_snapshots(self) -> AsyncVolumeSnapshotsResourceWithStreamingResponse: + return AsyncVolumeSnapshotsResourceWithStreamingResponse(self._cloud.volume_snapshots) diff --git a/src/gcore/resources/cloud/cost_reports.py b/src/gcore/resources/cloud/cost_reports.py new file mode 100644 index 00000000..c0f2f84b --- /dev/null +++ b/src/gcore/resources/cloud/cost_reports.py @@ -0,0 +1,855 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cloud import ( + cost_report_get_detailed_params, + cost_report_get_aggregated_params, + cost_report_get_aggregated_monthly_params, +) +from ..._base_client import make_request_options +from ...types.cloud.cost_report_detailed import CostReportDetailed +from ...types.cloud.cost_report_aggregated import CostReportAggregated +from ...types.cloud.cost_report_aggregated_monthly import CostReportAggregatedMonthly + +__all__ = ["CostReportsResource", "AsyncCostReportsResource"] + + +class CostReportsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CostReportsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return CostReportsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CostReportsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return CostReportsResourceWithStreamingResponse(self) + + def get_aggregated( + self, + *, + time_from: Union[str, datetime], + time_to: Union[str, datetime], + enable_last_day: bool | Omit = omit, + projects: Iterable[int] | Omit = omit, + regions: Iterable[int] | Omit = omit, + response_format: Literal["csv_totals", "json"] | Omit = omit, + rounding: bool | Omit = omit, + schema_filter: cost_report_get_aggregated_params.SchemaFilter | Omit = omit, + tags: cost_report_get_aggregated_params.Tags | Omit = omit, + types: List[ + Literal[ + "ai_cluster", + "ai_virtual_cluster", + "backup", + "baremetal", + "basic_vm", + "containers", + "dbaas_postgresql_connection_pooler", + "dbaas_postgresql_cpu", + "dbaas_postgresql_memory", + "dbaas_postgresql_public_network", + "dbaas_postgresql_volume", + "egress_traffic", + "external_ip", + "file_share", + "floatingip", + "functions", + "functions_calls", + "functions_traffic", + "image", + "inference", + "instance", + "load_balancer", + "log_index", + "snapshot", + "volume", + ] + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CostReportAggregated: + """Get cost report totals (aggregated costs) for a given period. + + Requested period + should not exceed 31 days. + + Note: This report assumes there are no active commit features in the billing + plan. If there are active commit features (pre-paid resources) in your plan, use + /v1/`reservation_cost_report`/totals, as the results from this report will not + be accurate. + + Data from the past hour may not reflect the full set of statistics. For the most + complete and accurate results, we recommend accessing the data at least one hour + after the relevant time period. Updates are generally available within a 24-hour + window, though timing can vary. Scheduled maintenance or other exceptions may + occasionally cause delays beyond 24 hours. + + Args: + time_from: The start date of the report period (ISO 8601). The report starts from the + beginning of this day in UTC. + + time_to: The end date of the report period (ISO 8601). The report ends just before the + beginning of this day in UTC. + + enable_last_day: Expenses for the last specified day are taken into account. As the default, + False. + + projects: List of project IDs + + regions: List of region IDs. + + response_format: Format of the response (csv or json). + + rounding: Round cost values to 5 decimal places. When false, returns full precision. + + schema_filter: Extended filter for field filtering. + + tags: Filter by tags + + types: List of resource types to be filtered in the report. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/cloud/v1/cost_report/totals", + body=maybe_transform( + { + "time_from": time_from, + "time_to": time_to, + "enable_last_day": enable_last_day, + "projects": projects, + "regions": regions, + "response_format": response_format, + "rounding": rounding, + "schema_filter": schema_filter, + "tags": tags, + "types": types, + }, + cost_report_get_aggregated_params.CostReportGetAggregatedParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CostReportAggregated, + ) + + def get_aggregated_monthly( + self, + *, + regions: Iterable[int] | Omit = omit, + response_format: Literal["csv_totals", "json"] | Omit = omit, + rounding: bool | Omit = omit, + schema_filter: cost_report_get_aggregated_monthly_params.SchemaFilter | Omit = omit, + tags: cost_report_get_aggregated_monthly_params.Tags | Omit = omit, + time_from: Union[str, datetime] | Omit = omit, + time_to: Union[str, datetime] | Omit = omit, + types: List[ + Literal[ + "ai_cluster", + "ai_virtual_cluster", + "backup", + "baremetal", + "basic_vm", + "containers", + "dbaas_postgresql_connection_pooler", + "dbaas_postgresql_cpu", + "dbaas_postgresql_memory", + "dbaas_postgresql_public_network", + "dbaas_postgresql_volume", + "egress_traffic", + "external_ip", + "file_share", + "floatingip", + "functions", + "functions_calls", + "functions_traffic", + "image", + "inference", + "instance", + "load_balancer", + "log_index", + "snapshot", + "volume", + ] + ] + | Omit = omit, + year_month: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CostReportAggregatedMonthly: + """ + Retrieve a detailed cost report totals for a specified month, which includes + both commit and pay-as-you-go (overcommit) prices. Additionally, it provides the + spent billing units (e.g., hours or GB) for resources. The "time_to" parameter + represents all days in the specified month. + + Data from the past hour may not reflect the full set of statistics. For the most + complete and accurate results, we recommend accessing the data at least one hour + after the relevant time period. Updates are generally available within a 24-hour + window, though timing can vary. Scheduled maintenance or other exceptions may + occasionally cause delays beyond 24 hours. + + Args: + regions: List of region IDs. + + response_format: Format of the response (`csv_totals` or json). + + rounding: Round cost values to 5 decimal places. When false, returns full precision. + + schema_filter: Extended filter for field filtering. + + tags: Filter by tags + + time_from: Deprecated. Use `year_month` instead. Beginning of the period: YYYY-mm + + time_to: Deprecated. Use `year_month` instead. End of the period: YYYY-mm + + types: List of resource types to be filtered in the report. + + year_month: Year and month in the format YYYY-MM + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/cloud/v1/reservation_cost_report/totals", + body=maybe_transform( + { + "regions": regions, + "response_format": response_format, + "rounding": rounding, + "schema_filter": schema_filter, + "tags": tags, + "time_from": time_from, + "time_to": time_to, + "types": types, + "year_month": year_month, + }, + cost_report_get_aggregated_monthly_params.CostReportGetAggregatedMonthlyParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CostReportAggregatedMonthly, + ) + + def get_detailed( + self, + *, + time_from: Union[str, datetime], + time_to: Union[str, datetime], + enable_last_day: bool | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + projects: Iterable[int] | Omit = omit, + regions: Iterable[int] | Omit = omit, + response_format: Literal["csv_records", "json"] | Omit = omit, + rounding: bool | Omit = omit, + schema_filter: cost_report_get_detailed_params.SchemaFilter | Omit = omit, + sorting: Iterable[cost_report_get_detailed_params.Sorting] | Omit = omit, + tags: cost_report_get_detailed_params.Tags | Omit = omit, + types: List[ + Literal[ + "ai_cluster", + "ai_virtual_cluster", + "backup", + "baremetal", + "basic_vm", + "containers", + "dbaas_postgresql_connection_pooler", + "dbaas_postgresql_cpu", + "dbaas_postgresql_memory", + "dbaas_postgresql_public_network", + "dbaas_postgresql_volume", + "egress_traffic", + "external_ip", + "file_share", + "floatingip", + "functions", + "functions_calls", + "functions_traffic", + "image", + "inference", + "instance", + "load_balancer", + "log_index", + "snapshot", + "volume", + ] + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CostReportDetailed: + """Get a detailed cost report for a given period and specific resources. + + Requested + period should not exceed 31 days. + + Note: This report assumes there are no active commit features in the billing + plan. If there are active commit features (pre-paid resources) in your plan, use + /v1/`reservation_cost_report`/totals, as the results from this report will not + be accurate. + + Data from the past hour may not reflect the full set of statistics. For the most + complete and accurate results, we recommend accessing the data at least one hour + after the relevant time period. Updates are generally available within a 24-hour + window, though timing can vary. Scheduled maintenance or other exceptions may + occasionally cause delays beyond 24 hours. + + Args: + time_from: The start date of the report period (ISO 8601). The report starts from the + beginning of this day in UTC. + + time_to: The end date of the report period (ISO 8601). The report ends just before the + beginning of this day in UTC. + + enable_last_day: Expenses for the last specified day are taken into account. As the default, + False. + + limit: The response resources limit. Defaults to 10. + + offset: The response resources offset. + + projects: List of project IDs + + regions: List of region IDs. + + response_format: Format of the response (csv or json). + + rounding: Round cost values to 5 decimal places. When false, returns full precision. + + schema_filter: Extended filter for field filtering. + + sorting: List of sorting filters (JSON objects) fields: project. directions: asc, desc. + + tags: Filter by tags + + types: List of resource types to be filtered in the report. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/cloud/v1/cost_report/resources", + body=maybe_transform( + { + "time_from": time_from, + "time_to": time_to, + "enable_last_day": enable_last_day, + "limit": limit, + "offset": offset, + "projects": projects, + "regions": regions, + "response_format": response_format, + "rounding": rounding, + "schema_filter": schema_filter, + "sorting": sorting, + "tags": tags, + "types": types, + }, + cost_report_get_detailed_params.CostReportGetDetailedParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CostReportDetailed, + ) + + +class AsyncCostReportsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCostReportsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncCostReportsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCostReportsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncCostReportsResourceWithStreamingResponse(self) + + async def get_aggregated( + self, + *, + time_from: Union[str, datetime], + time_to: Union[str, datetime], + enable_last_day: bool | Omit = omit, + projects: Iterable[int] | Omit = omit, + regions: Iterable[int] | Omit = omit, + response_format: Literal["csv_totals", "json"] | Omit = omit, + rounding: bool | Omit = omit, + schema_filter: cost_report_get_aggregated_params.SchemaFilter | Omit = omit, + tags: cost_report_get_aggregated_params.Tags | Omit = omit, + types: List[ + Literal[ + "ai_cluster", + "ai_virtual_cluster", + "backup", + "baremetal", + "basic_vm", + "containers", + "dbaas_postgresql_connection_pooler", + "dbaas_postgresql_cpu", + "dbaas_postgresql_memory", + "dbaas_postgresql_public_network", + "dbaas_postgresql_volume", + "egress_traffic", + "external_ip", + "file_share", + "floatingip", + "functions", + "functions_calls", + "functions_traffic", + "image", + "inference", + "instance", + "load_balancer", + "log_index", + "snapshot", + "volume", + ] + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CostReportAggregated: + """Get cost report totals (aggregated costs) for a given period. + + Requested period + should not exceed 31 days. + + Note: This report assumes there are no active commit features in the billing + plan. If there are active commit features (pre-paid resources) in your plan, use + /v1/`reservation_cost_report`/totals, as the results from this report will not + be accurate. + + Data from the past hour may not reflect the full set of statistics. For the most + complete and accurate results, we recommend accessing the data at least one hour + after the relevant time period. Updates are generally available within a 24-hour + window, though timing can vary. Scheduled maintenance or other exceptions may + occasionally cause delays beyond 24 hours. + + Args: + time_from: The start date of the report period (ISO 8601). The report starts from the + beginning of this day in UTC. + + time_to: The end date of the report period (ISO 8601). The report ends just before the + beginning of this day in UTC. + + enable_last_day: Expenses for the last specified day are taken into account. As the default, + False. + + projects: List of project IDs + + regions: List of region IDs. + + response_format: Format of the response (csv or json). + + rounding: Round cost values to 5 decimal places. When false, returns full precision. + + schema_filter: Extended filter for field filtering. + + tags: Filter by tags + + types: List of resource types to be filtered in the report. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/cloud/v1/cost_report/totals", + body=await async_maybe_transform( + { + "time_from": time_from, + "time_to": time_to, + "enable_last_day": enable_last_day, + "projects": projects, + "regions": regions, + "response_format": response_format, + "rounding": rounding, + "schema_filter": schema_filter, + "tags": tags, + "types": types, + }, + cost_report_get_aggregated_params.CostReportGetAggregatedParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CostReportAggregated, + ) + + async def get_aggregated_monthly( + self, + *, + regions: Iterable[int] | Omit = omit, + response_format: Literal["csv_totals", "json"] | Omit = omit, + rounding: bool | Omit = omit, + schema_filter: cost_report_get_aggregated_monthly_params.SchemaFilter | Omit = omit, + tags: cost_report_get_aggregated_monthly_params.Tags | Omit = omit, + time_from: Union[str, datetime] | Omit = omit, + time_to: Union[str, datetime] | Omit = omit, + types: List[ + Literal[ + "ai_cluster", + "ai_virtual_cluster", + "backup", + "baremetal", + "basic_vm", + "containers", + "dbaas_postgresql_connection_pooler", + "dbaas_postgresql_cpu", + "dbaas_postgresql_memory", + "dbaas_postgresql_public_network", + "dbaas_postgresql_volume", + "egress_traffic", + "external_ip", + "file_share", + "floatingip", + "functions", + "functions_calls", + "functions_traffic", + "image", + "inference", + "instance", + "load_balancer", + "log_index", + "snapshot", + "volume", + ] + ] + | Omit = omit, + year_month: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CostReportAggregatedMonthly: + """ + Retrieve a detailed cost report totals for a specified month, which includes + both commit and pay-as-you-go (overcommit) prices. Additionally, it provides the + spent billing units (e.g., hours or GB) for resources. The "time_to" parameter + represents all days in the specified month. + + Data from the past hour may not reflect the full set of statistics. For the most + complete and accurate results, we recommend accessing the data at least one hour + after the relevant time period. Updates are generally available within a 24-hour + window, though timing can vary. Scheduled maintenance or other exceptions may + occasionally cause delays beyond 24 hours. + + Args: + regions: List of region IDs. + + response_format: Format of the response (`csv_totals` or json). + + rounding: Round cost values to 5 decimal places. When false, returns full precision. + + schema_filter: Extended filter for field filtering. + + tags: Filter by tags + + time_from: Deprecated. Use `year_month` instead. Beginning of the period: YYYY-mm + + time_to: Deprecated. Use `year_month` instead. End of the period: YYYY-mm + + types: List of resource types to be filtered in the report. + + year_month: Year and month in the format YYYY-MM + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/cloud/v1/reservation_cost_report/totals", + body=await async_maybe_transform( + { + "regions": regions, + "response_format": response_format, + "rounding": rounding, + "schema_filter": schema_filter, + "tags": tags, + "time_from": time_from, + "time_to": time_to, + "types": types, + "year_month": year_month, + }, + cost_report_get_aggregated_monthly_params.CostReportGetAggregatedMonthlyParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CostReportAggregatedMonthly, + ) + + async def get_detailed( + self, + *, + time_from: Union[str, datetime], + time_to: Union[str, datetime], + enable_last_day: bool | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + projects: Iterable[int] | Omit = omit, + regions: Iterable[int] | Omit = omit, + response_format: Literal["csv_records", "json"] | Omit = omit, + rounding: bool | Omit = omit, + schema_filter: cost_report_get_detailed_params.SchemaFilter | Omit = omit, + sorting: Iterable[cost_report_get_detailed_params.Sorting] | Omit = omit, + tags: cost_report_get_detailed_params.Tags | Omit = omit, + types: List[ + Literal[ + "ai_cluster", + "ai_virtual_cluster", + "backup", + "baremetal", + "basic_vm", + "containers", + "dbaas_postgresql_connection_pooler", + "dbaas_postgresql_cpu", + "dbaas_postgresql_memory", + "dbaas_postgresql_public_network", + "dbaas_postgresql_volume", + "egress_traffic", + "external_ip", + "file_share", + "floatingip", + "functions", + "functions_calls", + "functions_traffic", + "image", + "inference", + "instance", + "load_balancer", + "log_index", + "snapshot", + "volume", + ] + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CostReportDetailed: + """Get a detailed cost report for a given period and specific resources. + + Requested + period should not exceed 31 days. + + Note: This report assumes there are no active commit features in the billing + plan. If there are active commit features (pre-paid resources) in your plan, use + /v1/`reservation_cost_report`/totals, as the results from this report will not + be accurate. + + Data from the past hour may not reflect the full set of statistics. For the most + complete and accurate results, we recommend accessing the data at least one hour + after the relevant time period. Updates are generally available within a 24-hour + window, though timing can vary. Scheduled maintenance or other exceptions may + occasionally cause delays beyond 24 hours. + + Args: + time_from: The start date of the report period (ISO 8601). The report starts from the + beginning of this day in UTC. + + time_to: The end date of the report period (ISO 8601). The report ends just before the + beginning of this day in UTC. + + enable_last_day: Expenses for the last specified day are taken into account. As the default, + False. + + limit: The response resources limit. Defaults to 10. + + offset: The response resources offset. + + projects: List of project IDs + + regions: List of region IDs. + + response_format: Format of the response (csv or json). + + rounding: Round cost values to 5 decimal places. When false, returns full precision. + + schema_filter: Extended filter for field filtering. + + sorting: List of sorting filters (JSON objects) fields: project. directions: asc, desc. + + tags: Filter by tags + + types: List of resource types to be filtered in the report. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/cloud/v1/cost_report/resources", + body=await async_maybe_transform( + { + "time_from": time_from, + "time_to": time_to, + "enable_last_day": enable_last_day, + "limit": limit, + "offset": offset, + "projects": projects, + "regions": regions, + "response_format": response_format, + "rounding": rounding, + "schema_filter": schema_filter, + "sorting": sorting, + "tags": tags, + "types": types, + }, + cost_report_get_detailed_params.CostReportGetDetailedParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CostReportDetailed, + ) + + +class CostReportsResourceWithRawResponse: + def __init__(self, cost_reports: CostReportsResource) -> None: + self._cost_reports = cost_reports + + self.get_aggregated = to_raw_response_wrapper( + cost_reports.get_aggregated, + ) + self.get_aggregated_monthly = to_raw_response_wrapper( + cost_reports.get_aggregated_monthly, + ) + self.get_detailed = to_raw_response_wrapper( + cost_reports.get_detailed, + ) + + +class AsyncCostReportsResourceWithRawResponse: + def __init__(self, cost_reports: AsyncCostReportsResource) -> None: + self._cost_reports = cost_reports + + self.get_aggregated = async_to_raw_response_wrapper( + cost_reports.get_aggregated, + ) + self.get_aggregated_monthly = async_to_raw_response_wrapper( + cost_reports.get_aggregated_monthly, + ) + self.get_detailed = async_to_raw_response_wrapper( + cost_reports.get_detailed, + ) + + +class CostReportsResourceWithStreamingResponse: + def __init__(self, cost_reports: CostReportsResource) -> None: + self._cost_reports = cost_reports + + self.get_aggregated = to_streamed_response_wrapper( + cost_reports.get_aggregated, + ) + self.get_aggregated_monthly = to_streamed_response_wrapper( + cost_reports.get_aggregated_monthly, + ) + self.get_detailed = to_streamed_response_wrapper( + cost_reports.get_detailed, + ) + + +class AsyncCostReportsResourceWithStreamingResponse: + def __init__(self, cost_reports: AsyncCostReportsResource) -> None: + self._cost_reports = cost_reports + + self.get_aggregated = async_to_streamed_response_wrapper( + cost_reports.get_aggregated, + ) + self.get_aggregated_monthly = async_to_streamed_response_wrapper( + cost_reports.get_aggregated_monthly, + ) + self.get_detailed = async_to_streamed_response_wrapper( + cost_reports.get_detailed, + ) diff --git a/src/gcore/resources/cloud/databases/__init__.py b/src/gcore/resources/cloud/databases/__init__.py new file mode 100644 index 00000000..6935a4f7 --- /dev/null +++ b/src/gcore/resources/cloud/databases/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .postgres import ( + PostgresResource, + AsyncPostgresResource, + PostgresResourceWithRawResponse, + AsyncPostgresResourceWithRawResponse, + PostgresResourceWithStreamingResponse, + AsyncPostgresResourceWithStreamingResponse, +) +from .databases import ( + DatabasesResource, + AsyncDatabasesResource, + DatabasesResourceWithRawResponse, + AsyncDatabasesResourceWithRawResponse, + DatabasesResourceWithStreamingResponse, + AsyncDatabasesResourceWithStreamingResponse, +) + +__all__ = [ + "PostgresResource", + "AsyncPostgresResource", + "PostgresResourceWithRawResponse", + "AsyncPostgresResourceWithRawResponse", + "PostgresResourceWithStreamingResponse", + "AsyncPostgresResourceWithStreamingResponse", + "DatabasesResource", + "AsyncDatabasesResource", + "DatabasesResourceWithRawResponse", + "AsyncDatabasesResourceWithRawResponse", + "DatabasesResourceWithStreamingResponse", + "AsyncDatabasesResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/databases/databases.py b/src/gcore/resources/cloud/databases/databases.py new file mode 100644 index 00000000..baacc4af --- /dev/null +++ b/src/gcore/resources/cloud/databases/databases.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from .postgres.postgres import ( + PostgresResource, + AsyncPostgresResource, + PostgresResourceWithRawResponse, + AsyncPostgresResourceWithRawResponse, + PostgresResourceWithStreamingResponse, + AsyncPostgresResourceWithStreamingResponse, +) + +__all__ = ["DatabasesResource", "AsyncDatabasesResource"] + + +class DatabasesResource(SyncAPIResource): + @cached_property + def postgres(self) -> PostgresResource: + return PostgresResource(self._client) + + @cached_property + def with_raw_response(self) -> DatabasesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return DatabasesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DatabasesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return DatabasesResourceWithStreamingResponse(self) + + +class AsyncDatabasesResource(AsyncAPIResource): + @cached_property + def postgres(self) -> AsyncPostgresResource: + return AsyncPostgresResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncDatabasesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncDatabasesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDatabasesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncDatabasesResourceWithStreamingResponse(self) + + +class DatabasesResourceWithRawResponse: + def __init__(self, databases: DatabasesResource) -> None: + self._databases = databases + + @cached_property + def postgres(self) -> PostgresResourceWithRawResponse: + return PostgresResourceWithRawResponse(self._databases.postgres) + + +class AsyncDatabasesResourceWithRawResponse: + def __init__(self, databases: AsyncDatabasesResource) -> None: + self._databases = databases + + @cached_property + def postgres(self) -> AsyncPostgresResourceWithRawResponse: + return AsyncPostgresResourceWithRawResponse(self._databases.postgres) + + +class DatabasesResourceWithStreamingResponse: + def __init__(self, databases: DatabasesResource) -> None: + self._databases = databases + + @cached_property + def postgres(self) -> PostgresResourceWithStreamingResponse: + return PostgresResourceWithStreamingResponse(self._databases.postgres) + + +class AsyncDatabasesResourceWithStreamingResponse: + def __init__(self, databases: AsyncDatabasesResource) -> None: + self._databases = databases + + @cached_property + def postgres(self) -> AsyncPostgresResourceWithStreamingResponse: + return AsyncPostgresResourceWithStreamingResponse(self._databases.postgres) diff --git a/src/gcore/resources/cloud/databases/postgres/__init__.py b/src/gcore/resources/cloud/databases/postgres/__init__.py new file mode 100644 index 00000000..63128146 --- /dev/null +++ b/src/gcore/resources/cloud/databases/postgres/__init__.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) +from .postgres import ( + PostgresResource, + AsyncPostgresResource, + PostgresResourceWithRawResponse, + AsyncPostgresResourceWithRawResponse, + PostgresResourceWithStreamingResponse, + AsyncPostgresResourceWithStreamingResponse, +) +from .configurations import ( + ConfigurationsResource, + AsyncConfigurationsResource, + ConfigurationsResourceWithRawResponse, + AsyncConfigurationsResourceWithRawResponse, + ConfigurationsResourceWithStreamingResponse, + AsyncConfigurationsResourceWithStreamingResponse, +) +from .custom_configurations import ( + CustomConfigurationsResource, + AsyncCustomConfigurationsResource, + CustomConfigurationsResourceWithRawResponse, + AsyncCustomConfigurationsResourceWithRawResponse, + CustomConfigurationsResourceWithStreamingResponse, + AsyncCustomConfigurationsResourceWithStreamingResponse, +) + +__all__ = [ + "ClustersResource", + "AsyncClustersResource", + "ClustersResourceWithRawResponse", + "AsyncClustersResourceWithRawResponse", + "ClustersResourceWithStreamingResponse", + "AsyncClustersResourceWithStreamingResponse", + "ConfigurationsResource", + "AsyncConfigurationsResource", + "ConfigurationsResourceWithRawResponse", + "AsyncConfigurationsResourceWithRawResponse", + "ConfigurationsResourceWithStreamingResponse", + "AsyncConfigurationsResourceWithStreamingResponse", + "CustomConfigurationsResource", + "AsyncCustomConfigurationsResource", + "CustomConfigurationsResourceWithRawResponse", + "AsyncCustomConfigurationsResourceWithRawResponse", + "CustomConfigurationsResourceWithStreamingResponse", + "AsyncCustomConfigurationsResourceWithStreamingResponse", + "PostgresResource", + "AsyncPostgresResource", + "PostgresResourceWithRawResponse", + "AsyncPostgresResourceWithRawResponse", + "PostgresResourceWithStreamingResponse", + "AsyncPostgresResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/databases/postgres/clusters/__init__.py b/src/gcore/resources/cloud/databases/postgres/clusters/__init__.py new file mode 100644 index 00000000..677f309e --- /dev/null +++ b/src/gcore/resources/cloud/databases/postgres/clusters/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) +from .user_credentials import ( + UserCredentialsResource, + AsyncUserCredentialsResource, + UserCredentialsResourceWithRawResponse, + AsyncUserCredentialsResourceWithRawResponse, + UserCredentialsResourceWithStreamingResponse, + AsyncUserCredentialsResourceWithStreamingResponse, +) + +__all__ = [ + "UserCredentialsResource", + "AsyncUserCredentialsResource", + "UserCredentialsResourceWithRawResponse", + "AsyncUserCredentialsResourceWithRawResponse", + "UserCredentialsResourceWithStreamingResponse", + "AsyncUserCredentialsResourceWithStreamingResponse", + "ClustersResource", + "AsyncClustersResource", + "ClustersResourceWithRawResponse", + "AsyncClustersResourceWithRawResponse", + "ClustersResourceWithStreamingResponse", + "AsyncClustersResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/databases/postgres/clusters/clusters.py b/src/gcore/resources/cloud/databases/postgres/clusters/clusters.py new file mode 100644 index 00000000..bb01ed8b --- /dev/null +++ b/src/gcore/resources/cloud/databases/postgres/clusters/clusters.py @@ -0,0 +1,716 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional + +import httpx + +from ......_types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ......_utils import maybe_transform, async_maybe_transform +from ......_compat import cached_property +from ......_resource import SyncAPIResource, AsyncAPIResource +from ......_response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ......pagination import SyncOffsetPage, AsyncOffsetPage +from .user_credentials import ( + UserCredentialsResource, + AsyncUserCredentialsResource, + UserCredentialsResourceWithRawResponse, + AsyncUserCredentialsResourceWithRawResponse, + UserCredentialsResourceWithStreamingResponse, + AsyncUserCredentialsResourceWithStreamingResponse, +) +from ......_base_client import AsyncPaginator, make_request_options +from ......types.cloud.task_id_list import TaskIDList +from ......types.cloud.databases.postgres import cluster_list_params, cluster_create_params, cluster_update_params +from ......types.cloud.databases.postgres.postgres_cluster import PostgresCluster +from ......types.cloud.databases.postgres.postgres_cluster_short import PostgresClusterShort + +__all__ = ["ClustersResource", "AsyncClustersResource"] + + +class ClustersResource(SyncAPIResource): + @cached_property + def user_credentials(self) -> UserCredentialsResource: + return UserCredentialsResource(self._client) + + @cached_property + def with_raw_response(self) -> ClustersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ClustersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ClustersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ClustersResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + flavor: cluster_create_params.Flavor, + high_availability: Optional[cluster_create_params.HighAvailability], + network: cluster_create_params.Network, + pg_server_configuration: cluster_create_params.PgServerConfiguration, + storage: cluster_create_params.Storage, + databases: Iterable[cluster_create_params.Database] | Omit = omit, + users: Iterable[cluster_create_params.User] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new PostgreSQL cluster with the specified configuration. + + Args: + cluster_name: PostgreSQL cluster name + + flavor: Instance RAM and CPU + + high_availability: High Availability settings + + pg_server_configuration: PosgtreSQL cluster configuration + + storage: Cluster's storage configuration + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}", + body=maybe_transform( + { + "cluster_name": cluster_name, + "flavor": flavor, + "high_availability": high_availability, + "network": network, + "pg_server_configuration": pg_server_configuration, + "storage": storage, + "databases": databases, + "users": users, + }, + cluster_create_params.ClusterCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + databases: Iterable[cluster_update_params.Database] | Omit = omit, + flavor: Optional[cluster_update_params.Flavor] | Omit = omit, + high_availability: Optional[cluster_update_params.HighAvailability] | Omit = omit, + network: Optional[cluster_update_params.Network] | Omit = omit, + pg_server_configuration: Optional[cluster_update_params.PgServerConfiguration] | Omit = omit, + storage: Optional[cluster_update_params.Storage] | Omit = omit, + users: Iterable[cluster_update_params.User] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Update the configuration of an existing PostgreSQL cluster. + + Args: + flavor: New instance RAM and CPU + + high_availability: New High Availability settings + + pg_server_configuration: New PosgtreSQL cluster configuration + + storage: New storage configuration + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return self._patch( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}/{cluster_name}", + body=maybe_transform( + { + "databases": databases, + "flavor": flavor, + "high_availability": high_availability, + "network": network, + "pg_server_configuration": pg_server_configuration, + "storage": storage, + "users": users, + }, + cluster_update_params.ClusterUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[PostgresClusterShort]: + """List all PostgreSQL clusters in the specified project and region. + + Results can be + filtered by search query and paginated. + + Args: + limit: Maximum number of clusters to return + + offset: Number of clusters to skip + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}", + page=SyncOffsetPage[PostgresClusterShort], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + cluster_list_params.ClusterListParams, + ), + ), + model=PostgresClusterShort, + ) + + def delete( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a PostgreSQL cluster and all its associated resources. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return self._delete( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}/{cluster_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PostgresCluster: + """ + Get detailed information about a specific PostgreSQL cluster. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return self._get( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}/{cluster_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PostgresCluster, + ) + + +class AsyncClustersResource(AsyncAPIResource): + @cached_property + def user_credentials(self) -> AsyncUserCredentialsResource: + return AsyncUserCredentialsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncClustersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncClustersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncClustersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncClustersResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + flavor: cluster_create_params.Flavor, + high_availability: Optional[cluster_create_params.HighAvailability], + network: cluster_create_params.Network, + pg_server_configuration: cluster_create_params.PgServerConfiguration, + storage: cluster_create_params.Storage, + databases: Iterable[cluster_create_params.Database] | Omit = omit, + users: Iterable[cluster_create_params.User] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new PostgreSQL cluster with the specified configuration. + + Args: + cluster_name: PostgreSQL cluster name + + flavor: Instance RAM and CPU + + high_availability: High Availability settings + + pg_server_configuration: PosgtreSQL cluster configuration + + storage: Cluster's storage configuration + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "cluster_name": cluster_name, + "flavor": flavor, + "high_availability": high_availability, + "network": network, + "pg_server_configuration": pg_server_configuration, + "storage": storage, + "databases": databases, + "users": users, + }, + cluster_create_params.ClusterCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + databases: Iterable[cluster_update_params.Database] | Omit = omit, + flavor: Optional[cluster_update_params.Flavor] | Omit = omit, + high_availability: Optional[cluster_update_params.HighAvailability] | Omit = omit, + network: Optional[cluster_update_params.Network] | Omit = omit, + pg_server_configuration: Optional[cluster_update_params.PgServerConfiguration] | Omit = omit, + storage: Optional[cluster_update_params.Storage] | Omit = omit, + users: Iterable[cluster_update_params.User] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Update the configuration of an existing PostgreSQL cluster. + + Args: + flavor: New instance RAM and CPU + + high_availability: New High Availability settings + + pg_server_configuration: New PosgtreSQL cluster configuration + + storage: New storage configuration + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return await self._patch( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}/{cluster_name}", + body=await async_maybe_transform( + { + "databases": databases, + "flavor": flavor, + "high_availability": high_availability, + "network": network, + "pg_server_configuration": pg_server_configuration, + "storage": storage, + "users": users, + }, + cluster_update_params.ClusterUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[PostgresClusterShort, AsyncOffsetPage[PostgresClusterShort]]: + """List all PostgreSQL clusters in the specified project and region. + + Results can be + filtered by search query and paginated. + + Args: + limit: Maximum number of clusters to return + + offset: Number of clusters to skip + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}", + page=AsyncOffsetPage[PostgresClusterShort], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + cluster_list_params.ClusterListParams, + ), + ), + model=PostgresClusterShort, + ) + + async def delete( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a PostgreSQL cluster and all its associated resources. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return await self._delete( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}/{cluster_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PostgresCluster: + """ + Get detailed information about a specific PostgreSQL cluster. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return await self._get( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}/{cluster_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PostgresCluster, + ) + + +class ClustersResourceWithRawResponse: + def __init__(self, clusters: ClustersResource) -> None: + self._clusters = clusters + + self.create = to_raw_response_wrapper( + clusters.create, + ) + self.update = to_raw_response_wrapper( + clusters.update, + ) + self.list = to_raw_response_wrapper( + clusters.list, + ) + self.delete = to_raw_response_wrapper( + clusters.delete, + ) + self.get = to_raw_response_wrapper( + clusters.get, + ) + + @cached_property + def user_credentials(self) -> UserCredentialsResourceWithRawResponse: + return UserCredentialsResourceWithRawResponse(self._clusters.user_credentials) + + +class AsyncClustersResourceWithRawResponse: + def __init__(self, clusters: AsyncClustersResource) -> None: + self._clusters = clusters + + self.create = async_to_raw_response_wrapper( + clusters.create, + ) + self.update = async_to_raw_response_wrapper( + clusters.update, + ) + self.list = async_to_raw_response_wrapper( + clusters.list, + ) + self.delete = async_to_raw_response_wrapper( + clusters.delete, + ) + self.get = async_to_raw_response_wrapper( + clusters.get, + ) + + @cached_property + def user_credentials(self) -> AsyncUserCredentialsResourceWithRawResponse: + return AsyncUserCredentialsResourceWithRawResponse(self._clusters.user_credentials) + + +class ClustersResourceWithStreamingResponse: + def __init__(self, clusters: ClustersResource) -> None: + self._clusters = clusters + + self.create = to_streamed_response_wrapper( + clusters.create, + ) + self.update = to_streamed_response_wrapper( + clusters.update, + ) + self.list = to_streamed_response_wrapper( + clusters.list, + ) + self.delete = to_streamed_response_wrapper( + clusters.delete, + ) + self.get = to_streamed_response_wrapper( + clusters.get, + ) + + @cached_property + def user_credentials(self) -> UserCredentialsResourceWithStreamingResponse: + return UserCredentialsResourceWithStreamingResponse(self._clusters.user_credentials) + + +class AsyncClustersResourceWithStreamingResponse: + def __init__(self, clusters: AsyncClustersResource) -> None: + self._clusters = clusters + + self.create = async_to_streamed_response_wrapper( + clusters.create, + ) + self.update = async_to_streamed_response_wrapper( + clusters.update, + ) + self.list = async_to_streamed_response_wrapper( + clusters.list, + ) + self.delete = async_to_streamed_response_wrapper( + clusters.delete, + ) + self.get = async_to_streamed_response_wrapper( + clusters.get, + ) + + @cached_property + def user_credentials(self) -> AsyncUserCredentialsResourceWithStreamingResponse: + return AsyncUserCredentialsResourceWithStreamingResponse(self._clusters.user_credentials) diff --git a/src/gcore/resources/cloud/databases/postgres/clusters/user_credentials.py b/src/gcore/resources/cloud/databases/postgres/clusters/user_credentials.py new file mode 100644 index 00000000..98ad25be --- /dev/null +++ b/src/gcore/resources/cloud/databases/postgres/clusters/user_credentials.py @@ -0,0 +1,281 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ......_types import Body, Query, Headers, NotGiven, not_given +from ......_compat import cached_property +from ......_resource import SyncAPIResource, AsyncAPIResource +from ......_response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ......_base_client import make_request_options +from ......types.cloud.databases.postgres.clusters.postgres_user_credentials import PostgresUserCredentials + +__all__ = ["UserCredentialsResource", "AsyncUserCredentialsResource"] + + +class UserCredentialsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> UserCredentialsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return UserCredentialsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> UserCredentialsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return UserCredentialsResourceWithStreamingResponse(self) + + def get( + self, + username: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PostgresUserCredentials: + """Get the credentials for a specific user in a PostgreSQL cluster. + + This endpoint + can only be used once per user. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not username: + raise ValueError(f"Expected a non-empty value for `username` but received {username!r}") + return self._get( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}/{cluster_name}/users/{username}/credentials", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PostgresUserCredentials, + ) + + def regenerate( + self, + username: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PostgresUserCredentials: + """ + Generate new credentials for a specific user in a PostgreSQL cluster. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not username: + raise ValueError(f"Expected a non-empty value for `username` but received {username!r}") + return self._post( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}/{cluster_name}/users/{username}/credentials", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PostgresUserCredentials, + ) + + +class AsyncUserCredentialsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncUserCredentialsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncUserCredentialsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncUserCredentialsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncUserCredentialsResourceWithStreamingResponse(self) + + async def get( + self, + username: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PostgresUserCredentials: + """Get the credentials for a specific user in a PostgreSQL cluster. + + This endpoint + can only be used once per user. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not username: + raise ValueError(f"Expected a non-empty value for `username` but received {username!r}") + return await self._get( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}/{cluster_name}/users/{username}/credentials", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PostgresUserCredentials, + ) + + async def regenerate( + self, + username: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PostgresUserCredentials: + """ + Generate new credentials for a specific user in a PostgreSQL cluster. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not username: + raise ValueError(f"Expected a non-empty value for `username` but received {username!r}") + return await self._post( + f"/cloud/v1/dbaas/postgres/clusters/{project_id}/{region_id}/{cluster_name}/users/{username}/credentials", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PostgresUserCredentials, + ) + + +class UserCredentialsResourceWithRawResponse: + def __init__(self, user_credentials: UserCredentialsResource) -> None: + self._user_credentials = user_credentials + + self.get = to_raw_response_wrapper( + user_credentials.get, + ) + self.regenerate = to_raw_response_wrapper( + user_credentials.regenerate, + ) + + +class AsyncUserCredentialsResourceWithRawResponse: + def __init__(self, user_credentials: AsyncUserCredentialsResource) -> None: + self._user_credentials = user_credentials + + self.get = async_to_raw_response_wrapper( + user_credentials.get, + ) + self.regenerate = async_to_raw_response_wrapper( + user_credentials.regenerate, + ) + + +class UserCredentialsResourceWithStreamingResponse: + def __init__(self, user_credentials: UserCredentialsResource) -> None: + self._user_credentials = user_credentials + + self.get = to_streamed_response_wrapper( + user_credentials.get, + ) + self.regenerate = to_streamed_response_wrapper( + user_credentials.regenerate, + ) + + +class AsyncUserCredentialsResourceWithStreamingResponse: + def __init__(self, user_credentials: AsyncUserCredentialsResource) -> None: + self._user_credentials = user_credentials + + self.get = async_to_streamed_response_wrapper( + user_credentials.get, + ) + self.regenerate = async_to_streamed_response_wrapper( + user_credentials.regenerate, + ) diff --git a/src/gcore/resources/cloud/databases/postgres/configurations.py b/src/gcore/resources/cloud/databases/postgres/configurations.py new file mode 100644 index 00000000..c9f30551 --- /dev/null +++ b/src/gcore/resources/cloud/databases/postgres/configurations.py @@ -0,0 +1,169 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import Body, Query, Headers, NotGiven, not_given +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.databases.postgres.postgres_configuration import PostgresConfiguration + +__all__ = ["ConfigurationsResource", "AsyncConfigurationsResource"] + + +class ConfigurationsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ConfigurationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ConfigurationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ConfigurationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ConfigurationsResourceWithStreamingResponse(self) + + def get( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PostgresConfiguration: + """ + Get all available PostgreSQL configurations for the specified region. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/dbaas/postgres/configuration/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PostgresConfiguration, + ) + + +class AsyncConfigurationsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncConfigurationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncConfigurationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncConfigurationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncConfigurationsResourceWithStreamingResponse(self) + + async def get( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PostgresConfiguration: + """ + Get all available PostgreSQL configurations for the specified region. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/dbaas/postgres/configuration/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PostgresConfiguration, + ) + + +class ConfigurationsResourceWithRawResponse: + def __init__(self, configurations: ConfigurationsResource) -> None: + self._configurations = configurations + + self.get = to_raw_response_wrapper( + configurations.get, + ) + + +class AsyncConfigurationsResourceWithRawResponse: + def __init__(self, configurations: AsyncConfigurationsResource) -> None: + self._configurations = configurations + + self.get = async_to_raw_response_wrapper( + configurations.get, + ) + + +class ConfigurationsResourceWithStreamingResponse: + def __init__(self, configurations: ConfigurationsResource) -> None: + self._configurations = configurations + + self.get = to_streamed_response_wrapper( + configurations.get, + ) + + +class AsyncConfigurationsResourceWithStreamingResponse: + def __init__(self, configurations: AsyncConfigurationsResource) -> None: + self._configurations = configurations + + self.get = async_to_streamed_response_wrapper( + configurations.get, + ) diff --git a/src/gcore/resources/cloud/databases/postgres/custom_configurations.py b/src/gcore/resources/cloud/databases/postgres/custom_configurations.py new file mode 100644 index 00000000..9ce396df --- /dev/null +++ b/src/gcore/resources/cloud/databases/postgres/custom_configurations.py @@ -0,0 +1,197 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import Body, Query, Headers, NotGiven, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.databases.postgres import custom_configuration_validate_params +from .....types.cloud.databases.postgres.pg_conf_validation import PgConfValidation + +__all__ = ["CustomConfigurationsResource", "AsyncCustomConfigurationsResource"] + + +class CustomConfigurationsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CustomConfigurationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return CustomConfigurationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CustomConfigurationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return CustomConfigurationsResourceWithStreamingResponse(self) + + def validate( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + pg_conf: str, + version: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PgConfValidation: + """ + Validate a custom PostgreSQL configuration file. + + Args: + pg_conf: PostgreSQL configuration + + version: PostgreSQL version + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/dbaas/postgres/validate_pg_conf/{project_id}/{region_id}", + body=maybe_transform( + { + "pg_conf": pg_conf, + "version": version, + }, + custom_configuration_validate_params.CustomConfigurationValidateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PgConfValidation, + ) + + +class AsyncCustomConfigurationsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCustomConfigurationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncCustomConfigurationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCustomConfigurationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncCustomConfigurationsResourceWithStreamingResponse(self) + + async def validate( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + pg_conf: str, + version: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PgConfValidation: + """ + Validate a custom PostgreSQL configuration file. + + Args: + pg_conf: PostgreSQL configuration + + version: PostgreSQL version + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/dbaas/postgres/validate_pg_conf/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "pg_conf": pg_conf, + "version": version, + }, + custom_configuration_validate_params.CustomConfigurationValidateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PgConfValidation, + ) + + +class CustomConfigurationsResourceWithRawResponse: + def __init__(self, custom_configurations: CustomConfigurationsResource) -> None: + self._custom_configurations = custom_configurations + + self.validate = to_raw_response_wrapper( + custom_configurations.validate, + ) + + +class AsyncCustomConfigurationsResourceWithRawResponse: + def __init__(self, custom_configurations: AsyncCustomConfigurationsResource) -> None: + self._custom_configurations = custom_configurations + + self.validate = async_to_raw_response_wrapper( + custom_configurations.validate, + ) + + +class CustomConfigurationsResourceWithStreamingResponse: + def __init__(self, custom_configurations: CustomConfigurationsResource) -> None: + self._custom_configurations = custom_configurations + + self.validate = to_streamed_response_wrapper( + custom_configurations.validate, + ) + + +class AsyncCustomConfigurationsResourceWithStreamingResponse: + def __init__(self, custom_configurations: AsyncCustomConfigurationsResource) -> None: + self._custom_configurations = custom_configurations + + self.validate = async_to_streamed_response_wrapper( + custom_configurations.validate, + ) diff --git a/src/gcore/resources/cloud/databases/postgres/postgres.py b/src/gcore/resources/cloud/databases/postgres/postgres.py new file mode 100644 index 00000000..ce9c32b7 --- /dev/null +++ b/src/gcore/resources/cloud/databases/postgres/postgres.py @@ -0,0 +1,166 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from .configurations import ( + ConfigurationsResource, + AsyncConfigurationsResource, + ConfigurationsResourceWithRawResponse, + AsyncConfigurationsResourceWithRawResponse, + ConfigurationsResourceWithStreamingResponse, + AsyncConfigurationsResourceWithStreamingResponse, +) +from .clusters.clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) +from .custom_configurations import ( + CustomConfigurationsResource, + AsyncCustomConfigurationsResource, + CustomConfigurationsResourceWithRawResponse, + AsyncCustomConfigurationsResourceWithRawResponse, + CustomConfigurationsResourceWithStreamingResponse, + AsyncCustomConfigurationsResourceWithStreamingResponse, +) + +__all__ = ["PostgresResource", "AsyncPostgresResource"] + + +class PostgresResource(SyncAPIResource): + @cached_property + def clusters(self) -> ClustersResource: + return ClustersResource(self._client) + + @cached_property + def configurations(self) -> ConfigurationsResource: + return ConfigurationsResource(self._client) + + @cached_property + def custom_configurations(self) -> CustomConfigurationsResource: + return CustomConfigurationsResource(self._client) + + @cached_property + def with_raw_response(self) -> PostgresResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return PostgresResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PostgresResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return PostgresResourceWithStreamingResponse(self) + + +class AsyncPostgresResource(AsyncAPIResource): + @cached_property + def clusters(self) -> AsyncClustersResource: + return AsyncClustersResource(self._client) + + @cached_property + def configurations(self) -> AsyncConfigurationsResource: + return AsyncConfigurationsResource(self._client) + + @cached_property + def custom_configurations(self) -> AsyncCustomConfigurationsResource: + return AsyncCustomConfigurationsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncPostgresResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncPostgresResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPostgresResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncPostgresResourceWithStreamingResponse(self) + + +class PostgresResourceWithRawResponse: + def __init__(self, postgres: PostgresResource) -> None: + self._postgres = postgres + + @cached_property + def clusters(self) -> ClustersResourceWithRawResponse: + return ClustersResourceWithRawResponse(self._postgres.clusters) + + @cached_property + def configurations(self) -> ConfigurationsResourceWithRawResponse: + return ConfigurationsResourceWithRawResponse(self._postgres.configurations) + + @cached_property + def custom_configurations(self) -> CustomConfigurationsResourceWithRawResponse: + return CustomConfigurationsResourceWithRawResponse(self._postgres.custom_configurations) + + +class AsyncPostgresResourceWithRawResponse: + def __init__(self, postgres: AsyncPostgresResource) -> None: + self._postgres = postgres + + @cached_property + def clusters(self) -> AsyncClustersResourceWithRawResponse: + return AsyncClustersResourceWithRawResponse(self._postgres.clusters) + + @cached_property + def configurations(self) -> AsyncConfigurationsResourceWithRawResponse: + return AsyncConfigurationsResourceWithRawResponse(self._postgres.configurations) + + @cached_property + def custom_configurations(self) -> AsyncCustomConfigurationsResourceWithRawResponse: + return AsyncCustomConfigurationsResourceWithRawResponse(self._postgres.custom_configurations) + + +class PostgresResourceWithStreamingResponse: + def __init__(self, postgres: PostgresResource) -> None: + self._postgres = postgres + + @cached_property + def clusters(self) -> ClustersResourceWithStreamingResponse: + return ClustersResourceWithStreamingResponse(self._postgres.clusters) + + @cached_property + def configurations(self) -> ConfigurationsResourceWithStreamingResponse: + return ConfigurationsResourceWithStreamingResponse(self._postgres.configurations) + + @cached_property + def custom_configurations(self) -> CustomConfigurationsResourceWithStreamingResponse: + return CustomConfigurationsResourceWithStreamingResponse(self._postgres.custom_configurations) + + +class AsyncPostgresResourceWithStreamingResponse: + def __init__(self, postgres: AsyncPostgresResource) -> None: + self._postgres = postgres + + @cached_property + def clusters(self) -> AsyncClustersResourceWithStreamingResponse: + return AsyncClustersResourceWithStreamingResponse(self._postgres.clusters) + + @cached_property + def configurations(self) -> AsyncConfigurationsResourceWithStreamingResponse: + return AsyncConfigurationsResourceWithStreamingResponse(self._postgres.configurations) + + @cached_property + def custom_configurations(self) -> AsyncCustomConfigurationsResourceWithStreamingResponse: + return AsyncCustomConfigurationsResourceWithStreamingResponse(self._postgres.custom_configurations) diff --git a/src/gcore/resources/cloud/file_shares/__init__.py b/src/gcore/resources/cloud/file_shares/__init__.py new file mode 100644 index 00000000..7026ea29 --- /dev/null +++ b/src/gcore/resources/cloud/file_shares/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .file_shares import ( + FileSharesResource, + AsyncFileSharesResource, + FileSharesResourceWithRawResponse, + AsyncFileSharesResourceWithRawResponse, + FileSharesResourceWithStreamingResponse, + AsyncFileSharesResourceWithStreamingResponse, +) +from .access_rules import ( + AccessRulesResource, + AsyncAccessRulesResource, + AccessRulesResourceWithRawResponse, + AsyncAccessRulesResourceWithRawResponse, + AccessRulesResourceWithStreamingResponse, + AsyncAccessRulesResourceWithStreamingResponse, +) + +__all__ = [ + "AccessRulesResource", + "AsyncAccessRulesResource", + "AccessRulesResourceWithRawResponse", + "AsyncAccessRulesResourceWithRawResponse", + "AccessRulesResourceWithStreamingResponse", + "AsyncAccessRulesResourceWithStreamingResponse", + "FileSharesResource", + "AsyncFileSharesResource", + "FileSharesResourceWithRawResponse", + "AsyncFileSharesResourceWithRawResponse", + "FileSharesResourceWithStreamingResponse", + "AsyncFileSharesResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/file_shares/access_rules.py b/src/gcore/resources/cloud/file_shares/access_rules.py new file mode 100644 index 00000000..6750a7c5 --- /dev/null +++ b/src/gcore/resources/cloud/file_shares/access_rules.py @@ -0,0 +1,434 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Query, Headers, NoneType, NotGiven, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.file_shares import access_rule_create_params +from ....types.cloud.file_shares.access_rule import AccessRule +from ....types.cloud.file_shares.access_rule_list import AccessRuleList + +__all__ = ["AccessRulesResource", "AsyncAccessRulesResource"] + + +class AccessRulesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> AccessRulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AccessRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AccessRulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AccessRulesResourceWithStreamingResponse(self) + + def create( + self, + file_share_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + access_mode: Literal["ro", "rw"], + ip_address: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AccessRule: + """ + Create file share access rule + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + access_mode: Access mode + + ip_address: Source IP or network + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + return self._post( + f"/cloud/v1/file_shares/{project_id}/{region_id}/{file_share_id}/access_rule", + body=maybe_transform( + { + "access_mode": access_mode, + "ip_address": ip_address, + }, + access_rule_create_params.AccessRuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AccessRule, + ) + + def list( + self, + file_share_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AccessRuleList: + """ + List file share access rules + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + return self._get( + f"/cloud/v1/file_shares/{project_id}/{region_id}/{file_share_id}/access_rule", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AccessRuleList, + ) + + def delete( + self, + access_rule_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + file_share_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete file share access rule + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + access_rule_id: Access Rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + if not access_rule_id: + raise ValueError(f"Expected a non-empty value for `access_rule_id` but received {access_rule_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v1/file_shares/{project_id}/{region_id}/{file_share_id}/access_rule/{access_rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncAccessRulesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAccessRulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncAccessRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAccessRulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncAccessRulesResourceWithStreamingResponse(self) + + async def create( + self, + file_share_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + access_mode: Literal["ro", "rw"], + ip_address: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AccessRule: + """ + Create file share access rule + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + access_mode: Access mode + + ip_address: Source IP or network + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + return await self._post( + f"/cloud/v1/file_shares/{project_id}/{region_id}/{file_share_id}/access_rule", + body=await async_maybe_transform( + { + "access_mode": access_mode, + "ip_address": ip_address, + }, + access_rule_create_params.AccessRuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AccessRule, + ) + + async def list( + self, + file_share_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AccessRuleList: + """ + List file share access rules + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + return await self._get( + f"/cloud/v1/file_shares/{project_id}/{region_id}/{file_share_id}/access_rule", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AccessRuleList, + ) + + async def delete( + self, + access_rule_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + file_share_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete file share access rule + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + access_rule_id: Access Rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + if not access_rule_id: + raise ValueError(f"Expected a non-empty value for `access_rule_id` but received {access_rule_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v1/file_shares/{project_id}/{region_id}/{file_share_id}/access_rule/{access_rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AccessRulesResourceWithRawResponse: + def __init__(self, access_rules: AccessRulesResource) -> None: + self._access_rules = access_rules + + self.create = to_raw_response_wrapper( + access_rules.create, + ) + self.list = to_raw_response_wrapper( + access_rules.list, + ) + self.delete = to_raw_response_wrapper( + access_rules.delete, + ) + + +class AsyncAccessRulesResourceWithRawResponse: + def __init__(self, access_rules: AsyncAccessRulesResource) -> None: + self._access_rules = access_rules + + self.create = async_to_raw_response_wrapper( + access_rules.create, + ) + self.list = async_to_raw_response_wrapper( + access_rules.list, + ) + self.delete = async_to_raw_response_wrapper( + access_rules.delete, + ) + + +class AccessRulesResourceWithStreamingResponse: + def __init__(self, access_rules: AccessRulesResource) -> None: + self._access_rules = access_rules + + self.create = to_streamed_response_wrapper( + access_rules.create, + ) + self.list = to_streamed_response_wrapper( + access_rules.list, + ) + self.delete = to_streamed_response_wrapper( + access_rules.delete, + ) + + +class AsyncAccessRulesResourceWithStreamingResponse: + def __init__(self, access_rules: AsyncAccessRulesResource) -> None: + self._access_rules = access_rules + + self.create = async_to_streamed_response_wrapper( + access_rules.create, + ) + self.list = async_to_streamed_response_wrapper( + access_rules.list, + ) + self.delete = async_to_streamed_response_wrapper( + access_rules.delete, + ) diff --git a/src/gcore/resources/cloud/file_shares/file_shares.py b/src/gcore/resources/cloud/file_shares/file_shares.py new file mode 100644 index 00000000..4e50acc9 --- /dev/null +++ b/src/gcore/resources/cloud/file_shares/file_shares.py @@ -0,0 +1,1106 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, overload + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import required_args, maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .access_rules import ( + AccessRulesResource, + AsyncAccessRulesResource, + AccessRulesResourceWithRawResponse, + AsyncAccessRulesResourceWithRawResponse, + AccessRulesResourceWithStreamingResponse, + AsyncAccessRulesResourceWithStreamingResponse, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ....types.cloud import ( + file_share_list_params, + file_share_create_params, + file_share_resize_params, + file_share_update_params, +) +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.file_share import FileShare +from ....types.cloud.task_id_list import TaskIDList +from ....types.cloud.tag_update_map_param import TagUpdateMapParam + +__all__ = ["FileSharesResource", "AsyncFileSharesResource"] + + +class FileSharesResource(SyncAPIResource): + @cached_property + def access_rules(self) -> AccessRulesResource: + return AccessRulesResource(self._client) + + @cached_property + def with_raw_response(self) -> FileSharesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return FileSharesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FileSharesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return FileSharesResourceWithStreamingResponse(self) + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + network: file_share_create_params.CreateStandardFileShareSerializerNetwork, + protocol: Literal["NFS"], + size: int, + access: Iterable[file_share_create_params.CreateStandardFileShareSerializerAccess] | Omit = omit, + tags: object | Omit = omit, + type_name: Literal["standard"] | Omit = omit, + volume_type: Literal["default_share_type"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create file share + + Args: + project_id: Project ID + + region_id: Region ID + + name: File share name + + network: File share network configuration + + protocol: File share protocol + + size: File share size in GiB + + access: Access Rules + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + type_name: Standard file share type + + volume_type: Deprecated. Use `type_name` instead. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + protocol: Literal["NFS"], + size: int, + share_settings: file_share_create_params.CreateVastFileShareSerializerShareSettings | Omit = omit, + tags: object | Omit = omit, + type_name: Literal["vast"] | Omit = omit, + volume_type: Literal["vast_share_type"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create file share + + Args: + project_id: Project ID + + region_id: Region ID + + name: File share name + + protocol: File share protocol + + size: File share size in GiB + + share_settings: Configuration settings for the share + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + type_name: Vast file share type + + volume_type: Deprecated. Use `type_name` instead. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["name", "network", "protocol", "size"], ["name", "protocol", "size"]) + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + network: file_share_create_params.CreateStandardFileShareSerializerNetwork | Omit = omit, + protocol: Literal["NFS"], + size: int, + access: Iterable[file_share_create_params.CreateStandardFileShareSerializerAccess] | Omit = omit, + tags: object | Omit = omit, + type_name: Literal["standard"] | Literal["vast"] | Omit = omit, + volume_type: Literal["default_share_type"] | Literal["vast_share_type"] | Omit = omit, + share_settings: file_share_create_params.CreateVastFileShareSerializerShareSettings | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/file_shares/{project_id}/{region_id}", + body=maybe_transform( + { + "name": name, + "network": network, + "protocol": protocol, + "size": size, + "access": access, + "tags": tags, + "type_name": type_name, + "volume_type": volume_type, + "share_settings": share_settings, + }, + file_share_create_params.FileShareCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + file_share_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + share_settings: file_share_update_params.ShareSettings | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Rename file share, update tags or set share specific properties + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + name: Name + + share_settings: Configuration settings for the share + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + return self._patch( + f"/cloud/v3/file_shares/{project_id}/{region_id}/{file_share_id}", + body=maybe_transform( + { + "name": name, + "share_settings": share_settings, + "tags": tags, + }, + file_share_update_params.FileShareUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + type_name: Literal["standard", "vast"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[FileShare]: + """ + List file shares + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Optional. Limit the number of returned items + + name: File share name. Uses partial match. + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + type_name: File share type name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/file_shares/{project_id}/{region_id}", + page=SyncOffsetPage[FileShare], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "name": name, + "offset": offset, + "type_name": type_name, + }, + file_share_list_params.FileShareListParams, + ), + ), + model=FileShare, + ) + + def delete( + self, + file_share_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete file share + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + return self._delete( + f"/cloud/v1/file_shares/{project_id}/{region_id}/{file_share_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + file_share_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> FileShare: + """ + Get file share + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + return self._get( + f"/cloud/v1/file_shares/{project_id}/{region_id}/{file_share_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FileShare, + ) + + def resize( + self, + file_share_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + size: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Resize file share + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + size: File Share new size in GiB. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + return self._post( + f"/cloud/v1/file_shares/{project_id}/{region_id}/{file_share_id}/extend", + body=maybe_transform({"size": size}, file_share_resize_params.FileShareResizeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncFileSharesResource(AsyncAPIResource): + @cached_property + def access_rules(self) -> AsyncAccessRulesResource: + return AsyncAccessRulesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncFileSharesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncFileSharesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFileSharesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncFileSharesResourceWithStreamingResponse(self) + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + network: file_share_create_params.CreateStandardFileShareSerializerNetwork, + protocol: Literal["NFS"], + size: int, + access: Iterable[file_share_create_params.CreateStandardFileShareSerializerAccess] | Omit = omit, + tags: object | Omit = omit, + type_name: Literal["standard"] | Omit = omit, + volume_type: Literal["default_share_type"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create file share + + Args: + project_id: Project ID + + region_id: Region ID + + name: File share name + + network: File share network configuration + + protocol: File share protocol + + size: File share size in GiB + + access: Access Rules + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + type_name: Standard file share type + + volume_type: Deprecated. Use `type_name` instead. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + protocol: Literal["NFS"], + size: int, + share_settings: file_share_create_params.CreateVastFileShareSerializerShareSettings | Omit = omit, + tags: object | Omit = omit, + type_name: Literal["vast"] | Omit = omit, + volume_type: Literal["vast_share_type"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create file share + + Args: + project_id: Project ID + + region_id: Region ID + + name: File share name + + protocol: File share protocol + + size: File share size in GiB + + share_settings: Configuration settings for the share + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + type_name: Vast file share type + + volume_type: Deprecated. Use `type_name` instead. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["name", "network", "protocol", "size"], ["name", "protocol", "size"]) + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + network: file_share_create_params.CreateStandardFileShareSerializerNetwork | Omit = omit, + protocol: Literal["NFS"], + size: int, + access: Iterable[file_share_create_params.CreateStandardFileShareSerializerAccess] | Omit = omit, + tags: object | Omit = omit, + type_name: Literal["standard"] | Literal["vast"] | Omit = omit, + volume_type: Literal["default_share_type"] | Literal["vast_share_type"] | Omit = omit, + share_settings: file_share_create_params.CreateVastFileShareSerializerShareSettings | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/file_shares/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "name": name, + "network": network, + "protocol": protocol, + "size": size, + "access": access, + "tags": tags, + "type_name": type_name, + "volume_type": volume_type, + "share_settings": share_settings, + }, + file_share_create_params.FileShareCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + file_share_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + share_settings: file_share_update_params.ShareSettings | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Rename file share, update tags or set share specific properties + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + name: Name + + share_settings: Configuration settings for the share + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + return await self._patch( + f"/cloud/v3/file_shares/{project_id}/{region_id}/{file_share_id}", + body=await async_maybe_transform( + { + "name": name, + "share_settings": share_settings, + "tags": tags, + }, + file_share_update_params.FileShareUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + type_name: Literal["standard", "vast"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[FileShare, AsyncOffsetPage[FileShare]]: + """ + List file shares + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Optional. Limit the number of returned items + + name: File share name. Uses partial match. + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + type_name: File share type name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/file_shares/{project_id}/{region_id}", + page=AsyncOffsetPage[FileShare], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "name": name, + "offset": offset, + "type_name": type_name, + }, + file_share_list_params.FileShareListParams, + ), + ), + model=FileShare, + ) + + async def delete( + self, + file_share_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete file share + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + return await self._delete( + f"/cloud/v1/file_shares/{project_id}/{region_id}/{file_share_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + file_share_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> FileShare: + """ + Get file share + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + return await self._get( + f"/cloud/v1/file_shares/{project_id}/{region_id}/{file_share_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FileShare, + ) + + async def resize( + self, + file_share_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + size: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Resize file share + + Args: + project_id: Project ID + + region_id: Region ID + + file_share_id: File Share ID + + size: File Share new size in GiB. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not file_share_id: + raise ValueError(f"Expected a non-empty value for `file_share_id` but received {file_share_id!r}") + return await self._post( + f"/cloud/v1/file_shares/{project_id}/{region_id}/{file_share_id}/extend", + body=await async_maybe_transform({"size": size}, file_share_resize_params.FileShareResizeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class FileSharesResourceWithRawResponse: + def __init__(self, file_shares: FileSharesResource) -> None: + self._file_shares = file_shares + + self.create = to_raw_response_wrapper( + file_shares.create, + ) + self.update = to_raw_response_wrapper( + file_shares.update, + ) + self.list = to_raw_response_wrapper( + file_shares.list, + ) + self.delete = to_raw_response_wrapper( + file_shares.delete, + ) + self.get = to_raw_response_wrapper( + file_shares.get, + ) + self.resize = to_raw_response_wrapper( + file_shares.resize, + ) + + @cached_property + def access_rules(self) -> AccessRulesResourceWithRawResponse: + return AccessRulesResourceWithRawResponse(self._file_shares.access_rules) + + +class AsyncFileSharesResourceWithRawResponse: + def __init__(self, file_shares: AsyncFileSharesResource) -> None: + self._file_shares = file_shares + + self.create = async_to_raw_response_wrapper( + file_shares.create, + ) + self.update = async_to_raw_response_wrapper( + file_shares.update, + ) + self.list = async_to_raw_response_wrapper( + file_shares.list, + ) + self.delete = async_to_raw_response_wrapper( + file_shares.delete, + ) + self.get = async_to_raw_response_wrapper( + file_shares.get, + ) + self.resize = async_to_raw_response_wrapper( + file_shares.resize, + ) + + @cached_property + def access_rules(self) -> AsyncAccessRulesResourceWithRawResponse: + return AsyncAccessRulesResourceWithRawResponse(self._file_shares.access_rules) + + +class FileSharesResourceWithStreamingResponse: + def __init__(self, file_shares: FileSharesResource) -> None: + self._file_shares = file_shares + + self.create = to_streamed_response_wrapper( + file_shares.create, + ) + self.update = to_streamed_response_wrapper( + file_shares.update, + ) + self.list = to_streamed_response_wrapper( + file_shares.list, + ) + self.delete = to_streamed_response_wrapper( + file_shares.delete, + ) + self.get = to_streamed_response_wrapper( + file_shares.get, + ) + self.resize = to_streamed_response_wrapper( + file_shares.resize, + ) + + @cached_property + def access_rules(self) -> AccessRulesResourceWithStreamingResponse: + return AccessRulesResourceWithStreamingResponse(self._file_shares.access_rules) + + +class AsyncFileSharesResourceWithStreamingResponse: + def __init__(self, file_shares: AsyncFileSharesResource) -> None: + self._file_shares = file_shares + + self.create = async_to_streamed_response_wrapper( + file_shares.create, + ) + self.update = async_to_streamed_response_wrapper( + file_shares.update, + ) + self.list = async_to_streamed_response_wrapper( + file_shares.list, + ) + self.delete = async_to_streamed_response_wrapper( + file_shares.delete, + ) + self.get = async_to_streamed_response_wrapper( + file_shares.get, + ) + self.resize = async_to_streamed_response_wrapper( + file_shares.resize, + ) + + @cached_property + def access_rules(self) -> AsyncAccessRulesResourceWithStreamingResponse: + return AsyncAccessRulesResourceWithStreamingResponse(self._file_shares.access_rules) diff --git a/src/gcore/resources/cloud/floating_ips.py b/src/gcore/resources/cloud/floating_ips.py new file mode 100644 index 00000000..fe753423 --- /dev/null +++ b/src/gcore/resources/cloud/floating_ips.py @@ -0,0 +1,1129 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import typing_extensions +from typing import Optional + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ...types.cloud import ( + FloatingIPStatus, + floating_ip_list_params, + floating_ip_assign_params, + floating_ip_create_params, + floating_ip_update_params, +) +from ..._base_client import AsyncPaginator, make_request_options +from ...types.cloud.floating_ip import FloatingIP +from ...types.cloud.task_id_list import TaskIDList +from ...types.cloud.floating_ip_status import FloatingIPStatus +from ...types.cloud.floating_ip_detailed import FloatingIPDetailed +from ...types.cloud.tag_update_map_param import TagUpdateMapParam + +__all__ = ["FloatingIPsResource", "AsyncFloatingIPsResource"] + + +class FloatingIPsResource(SyncAPIResource): + """A floating IP is a static IP address that points to one of your Instances. + + It allows you to redirect network traffic to any of your Instances in the same datacenter. + """ + + @cached_property + def with_raw_response(self) -> FloatingIPsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return FloatingIPsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FloatingIPsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return FloatingIPsResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + fixed_ip_address: Optional[str] | Omit = omit, + port_id: Optional[str] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create floating IP + + Args: + project_id: Project ID + + region_id: Region ID + + fixed_ip_address: If the port has multiple IP addresses, a specific one can be selected using this + field. If not specified, the first IP in the port's list will be used by + default. + + port_id: If provided, the floating IP will be immediately attached to the specified port. + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/floatingips/{project_id}/{region_id}", + body=maybe_transform( + { + "fixed_ip_address": fixed_ip_address, + "port_id": port_id, + "tags": tags, + }, + floating_ip_create_params.FloatingIPCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + floating_ip_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + fixed_ip_address: Optional[str] | Omit = omit, + port_id: Optional[str] | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """This endpoint updates the association and tags of an existing Floating IP. + + The + behavior depends on the current association state and the provided fields: + + Parameters: + + `port_id`: The unique identifier of the network interface (port) to which the + Floating IP should be assigned. This ID can be retrieved from the "Get instance" + or "List network interfaces" endpoints. + + `fixed_ip_address`: The private IP address assigned to the network interface. + This must be one of the IP addresses currently assigned to the specified port. + You can retrieve available fixed IP addresses from the "Get instance" or "List + network interfaces" endpoints. + + When the Floating IP has no port associated (`port_id` is null): + + - Patch with both `port_id` and `fixed_ip_address`: Assign the Floating IP to + the specified port and the provided `fixed_ip_address`, if that + `fixed_ip_address` exists on the port and is not yet used by another Floating + IP. + - Patch with `port_id` only (`fixed_ip_address` omitted): Assign the Floating IP + to the specified port using the first available IPv4 fixed IP of that port. + + When the Floating IP is already associated with a port: + + - Patch with both `port_id` and `fixed_ip_address`: Re-assign the Floating IP to + the specified port and address if all validations pass. + - Patch with `port_id` only (`fixed_ip_address` omitted): Re-assign the Floating + IP to the specified port using the first available IPv4 fixed IP of that port. + - Patch with `port_id` = null: Unassign the Floating IP from its current port. + + Tags: + + - You can update tags alongside association changes. Tags are provided as a list + of key-value pairs. + + Idempotency and task creation: + + - No worker task is created if the requested state is already actual, i.e., the + requested `port_id` equals the current `port_id` and/or the requested + `fixed_ip_address` equals the current `fixed_ip_address`, and the tags already + match the current tags. In such cases, the endpoint returns an empty tasks + list. + + Args: + project_id: Project ID + + region_id: Region ID + + floating_ip_id: Floating IP ID + + fixed_ip_address: Fixed IP address + + port_id: Port ID + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not floating_ip_id: + raise ValueError(f"Expected a non-empty value for `floating_ip_id` but received {floating_ip_id!r}") + return self._patch( + f"/cloud/v2/floatingips/{project_id}/{region_id}/{floating_ip_id}", + body=maybe_transform( + { + "fixed_ip_address": fixed_ip_address, + "port_id": port_id, + "tags": tags, + }, + floating_ip_update_params.FloatingIPUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + status: FloatingIPStatus | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[FloatingIPDetailed]: + """ + List floating IPs + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + status: Filter by floating IP status. DOWN - unassigned (available). ACTIVE - attached + to a port (in use). ERROR - error state. + + tag_key: Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2 + + tag_key_value: Optional. Filter by tag key-value pairs. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/floatingips/{project_id}/{region_id}", + page=SyncOffsetPage[FloatingIPDetailed], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + "status": status, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + }, + floating_ip_list_params.FloatingIPListParams, + ), + ), + model=FloatingIPDetailed, + ) + + def delete( + self, + floating_ip_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete floating IP + + Args: + project_id: Project ID + + region_id: Region ID + + floating_ip_id: Floating IP ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not floating_ip_id: + raise ValueError(f"Expected a non-empty value for `floating_ip_id` but received {floating_ip_id!r}") + return self._delete( + f"/cloud/v1/floatingips/{project_id}/{region_id}/{floating_ip_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + @typing_extensions.deprecated("deprecated") + def assign( + self, + floating_ip_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + port_id: str, + fixed_ip_address: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> FloatingIP: + """ + Assign floating IP to instance or loadbalancer. + + **Deprecated**: Use + `PATCH /v2/floatingips/{project_id}/{region_id}/{floating_ip_id}` instead. + + Args: + project_id: Project ID + + region_id: Region ID + + floating_ip_id: Floating IP ID + + port_id: Port ID + + fixed_ip_address: Fixed IP address + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not floating_ip_id: + raise ValueError(f"Expected a non-empty value for `floating_ip_id` but received {floating_ip_id!r}") + return self._post( + f"/cloud/v1/floatingips/{project_id}/{region_id}/{floating_ip_id}/assign", + body=maybe_transform( + { + "port_id": port_id, + "fixed_ip_address": fixed_ip_address, + }, + floating_ip_assign_params.FloatingIPAssignParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FloatingIP, + ) + + def get( + self, + floating_ip_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> FloatingIP: + """ + Get floating IP + + Args: + project_id: Project ID + + region_id: Region ID + + floating_ip_id: Floating IP ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not floating_ip_id: + raise ValueError(f"Expected a non-empty value for `floating_ip_id` but received {floating_ip_id!r}") + return self._get( + f"/cloud/v1/floatingips/{project_id}/{region_id}/{floating_ip_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FloatingIP, + ) + + @typing_extensions.deprecated("deprecated") + def unassign( + self, + floating_ip_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> FloatingIP: + """ + **Deprecated**: Use + `PATCH /v2/floatingips/{project_id}/{region_id}/{floating_ip_id}` instead. + + Args: + project_id: Project ID + + region_id: Region ID + + floating_ip_id: Floating IP ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not floating_ip_id: + raise ValueError(f"Expected a non-empty value for `floating_ip_id` but received {floating_ip_id!r}") + return self._post( + f"/cloud/v1/floatingips/{project_id}/{region_id}/{floating_ip_id}/unassign", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FloatingIP, + ) + + +class AsyncFloatingIPsResource(AsyncAPIResource): + """A floating IP is a static IP address that points to one of your Instances. + + It allows you to redirect network traffic to any of your Instances in the same datacenter. + """ + + @cached_property + def with_raw_response(self) -> AsyncFloatingIPsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncFloatingIPsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFloatingIPsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncFloatingIPsResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + fixed_ip_address: Optional[str] | Omit = omit, + port_id: Optional[str] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create floating IP + + Args: + project_id: Project ID + + region_id: Region ID + + fixed_ip_address: If the port has multiple IP addresses, a specific one can be selected using this + field. If not specified, the first IP in the port's list will be used by + default. + + port_id: If provided, the floating IP will be immediately attached to the specified port. + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/floatingips/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "fixed_ip_address": fixed_ip_address, + "port_id": port_id, + "tags": tags, + }, + floating_ip_create_params.FloatingIPCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + floating_ip_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + fixed_ip_address: Optional[str] | Omit = omit, + port_id: Optional[str] | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """This endpoint updates the association and tags of an existing Floating IP. + + The + behavior depends on the current association state and the provided fields: + + Parameters: + + `port_id`: The unique identifier of the network interface (port) to which the + Floating IP should be assigned. This ID can be retrieved from the "Get instance" + or "List network interfaces" endpoints. + + `fixed_ip_address`: The private IP address assigned to the network interface. + This must be one of the IP addresses currently assigned to the specified port. + You can retrieve available fixed IP addresses from the "Get instance" or "List + network interfaces" endpoints. + + When the Floating IP has no port associated (`port_id` is null): + + - Patch with both `port_id` and `fixed_ip_address`: Assign the Floating IP to + the specified port and the provided `fixed_ip_address`, if that + `fixed_ip_address` exists on the port and is not yet used by another Floating + IP. + - Patch with `port_id` only (`fixed_ip_address` omitted): Assign the Floating IP + to the specified port using the first available IPv4 fixed IP of that port. + + When the Floating IP is already associated with a port: + + - Patch with both `port_id` and `fixed_ip_address`: Re-assign the Floating IP to + the specified port and address if all validations pass. + - Patch with `port_id` only (`fixed_ip_address` omitted): Re-assign the Floating + IP to the specified port using the first available IPv4 fixed IP of that port. + - Patch with `port_id` = null: Unassign the Floating IP from its current port. + + Tags: + + - You can update tags alongside association changes. Tags are provided as a list + of key-value pairs. + + Idempotency and task creation: + + - No worker task is created if the requested state is already actual, i.e., the + requested `port_id` equals the current `port_id` and/or the requested + `fixed_ip_address` equals the current `fixed_ip_address`, and the tags already + match the current tags. In such cases, the endpoint returns an empty tasks + list. + + Args: + project_id: Project ID + + region_id: Region ID + + floating_ip_id: Floating IP ID + + fixed_ip_address: Fixed IP address + + port_id: Port ID + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not floating_ip_id: + raise ValueError(f"Expected a non-empty value for `floating_ip_id` but received {floating_ip_id!r}") + return await self._patch( + f"/cloud/v2/floatingips/{project_id}/{region_id}/{floating_ip_id}", + body=await async_maybe_transform( + { + "fixed_ip_address": fixed_ip_address, + "port_id": port_id, + "tags": tags, + }, + floating_ip_update_params.FloatingIPUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + status: FloatingIPStatus | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[FloatingIPDetailed, AsyncOffsetPage[FloatingIPDetailed]]: + """ + List floating IPs + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + status: Filter by floating IP status. DOWN - unassigned (available). ACTIVE - attached + to a port (in use). ERROR - error state. + + tag_key: Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2 + + tag_key_value: Optional. Filter by tag key-value pairs. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/floatingips/{project_id}/{region_id}", + page=AsyncOffsetPage[FloatingIPDetailed], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + "status": status, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + }, + floating_ip_list_params.FloatingIPListParams, + ), + ), + model=FloatingIPDetailed, + ) + + async def delete( + self, + floating_ip_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete floating IP + + Args: + project_id: Project ID + + region_id: Region ID + + floating_ip_id: Floating IP ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not floating_ip_id: + raise ValueError(f"Expected a non-empty value for `floating_ip_id` but received {floating_ip_id!r}") + return await self._delete( + f"/cloud/v1/floatingips/{project_id}/{region_id}/{floating_ip_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + @typing_extensions.deprecated("deprecated") + async def assign( + self, + floating_ip_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + port_id: str, + fixed_ip_address: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> FloatingIP: + """ + Assign floating IP to instance or loadbalancer. + + **Deprecated**: Use + `PATCH /v2/floatingips/{project_id}/{region_id}/{floating_ip_id}` instead. + + Args: + project_id: Project ID + + region_id: Region ID + + floating_ip_id: Floating IP ID + + port_id: Port ID + + fixed_ip_address: Fixed IP address + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not floating_ip_id: + raise ValueError(f"Expected a non-empty value for `floating_ip_id` but received {floating_ip_id!r}") + return await self._post( + f"/cloud/v1/floatingips/{project_id}/{region_id}/{floating_ip_id}/assign", + body=await async_maybe_transform( + { + "port_id": port_id, + "fixed_ip_address": fixed_ip_address, + }, + floating_ip_assign_params.FloatingIPAssignParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FloatingIP, + ) + + async def get( + self, + floating_ip_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> FloatingIP: + """ + Get floating IP + + Args: + project_id: Project ID + + region_id: Region ID + + floating_ip_id: Floating IP ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not floating_ip_id: + raise ValueError(f"Expected a non-empty value for `floating_ip_id` but received {floating_ip_id!r}") + return await self._get( + f"/cloud/v1/floatingips/{project_id}/{region_id}/{floating_ip_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FloatingIP, + ) + + @typing_extensions.deprecated("deprecated") + async def unassign( + self, + floating_ip_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> FloatingIP: + """ + **Deprecated**: Use + `PATCH /v2/floatingips/{project_id}/{region_id}/{floating_ip_id}` instead. + + Args: + project_id: Project ID + + region_id: Region ID + + floating_ip_id: Floating IP ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not floating_ip_id: + raise ValueError(f"Expected a non-empty value for `floating_ip_id` but received {floating_ip_id!r}") + return await self._post( + f"/cloud/v1/floatingips/{project_id}/{region_id}/{floating_ip_id}/unassign", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FloatingIP, + ) + + +class FloatingIPsResourceWithRawResponse: + def __init__(self, floating_ips: FloatingIPsResource) -> None: + self._floating_ips = floating_ips + + self.create = to_raw_response_wrapper( + floating_ips.create, + ) + self.update = to_raw_response_wrapper( + floating_ips.update, + ) + self.list = to_raw_response_wrapper( + floating_ips.list, + ) + self.delete = to_raw_response_wrapper( + floating_ips.delete, + ) + self.assign = ( # pyright: ignore[reportDeprecated] + to_raw_response_wrapper( + floating_ips.assign, # pyright: ignore[reportDeprecated], + ) + ) + self.get = to_raw_response_wrapper( + floating_ips.get, + ) + self.unassign = ( # pyright: ignore[reportDeprecated] + to_raw_response_wrapper( + floating_ips.unassign, # pyright: ignore[reportDeprecated], + ) + ) + + +class AsyncFloatingIPsResourceWithRawResponse: + def __init__(self, floating_ips: AsyncFloatingIPsResource) -> None: + self._floating_ips = floating_ips + + self.create = async_to_raw_response_wrapper( + floating_ips.create, + ) + self.update = async_to_raw_response_wrapper( + floating_ips.update, + ) + self.list = async_to_raw_response_wrapper( + floating_ips.list, + ) + self.delete = async_to_raw_response_wrapper( + floating_ips.delete, + ) + self.assign = ( # pyright: ignore[reportDeprecated] + async_to_raw_response_wrapper( + floating_ips.assign, # pyright: ignore[reportDeprecated], + ) + ) + self.get = async_to_raw_response_wrapper( + floating_ips.get, + ) + self.unassign = ( # pyright: ignore[reportDeprecated] + async_to_raw_response_wrapper( + floating_ips.unassign, # pyright: ignore[reportDeprecated], + ) + ) + + +class FloatingIPsResourceWithStreamingResponse: + def __init__(self, floating_ips: FloatingIPsResource) -> None: + self._floating_ips = floating_ips + + self.create = to_streamed_response_wrapper( + floating_ips.create, + ) + self.update = to_streamed_response_wrapper( + floating_ips.update, + ) + self.list = to_streamed_response_wrapper( + floating_ips.list, + ) + self.delete = to_streamed_response_wrapper( + floating_ips.delete, + ) + self.assign = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + floating_ips.assign, # pyright: ignore[reportDeprecated], + ) + ) + self.get = to_streamed_response_wrapper( + floating_ips.get, + ) + self.unassign = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + floating_ips.unassign, # pyright: ignore[reportDeprecated], + ) + ) + + +class AsyncFloatingIPsResourceWithStreamingResponse: + def __init__(self, floating_ips: AsyncFloatingIPsResource) -> None: + self._floating_ips = floating_ips + + self.create = async_to_streamed_response_wrapper( + floating_ips.create, + ) + self.update = async_to_streamed_response_wrapper( + floating_ips.update, + ) + self.list = async_to_streamed_response_wrapper( + floating_ips.list, + ) + self.delete = async_to_streamed_response_wrapper( + floating_ips.delete, + ) + self.assign = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + floating_ips.assign, # pyright: ignore[reportDeprecated], + ) + ) + self.get = async_to_streamed_response_wrapper( + floating_ips.get, + ) + self.unassign = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + floating_ips.unassign, # pyright: ignore[reportDeprecated], + ) + ) diff --git a/src/gcore/resources/cloud/gpu_baremetal/__init__.py b/src/gcore/resources/cloud/gpu_baremetal/__init__.py new file mode 100644 index 00000000..d8e97060 --- /dev/null +++ b/src/gcore/resources/cloud/gpu_baremetal/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) +from .gpu_baremetal import ( + GPUBaremetalResource, + AsyncGPUBaremetalResource, + GPUBaremetalResourceWithRawResponse, + AsyncGPUBaremetalResourceWithRawResponse, + GPUBaremetalResourceWithStreamingResponse, + AsyncGPUBaremetalResourceWithStreamingResponse, +) + +__all__ = [ + "ClustersResource", + "AsyncClustersResource", + "ClustersResourceWithRawResponse", + "AsyncClustersResourceWithRawResponse", + "ClustersResourceWithStreamingResponse", + "AsyncClustersResourceWithStreamingResponse", + "GPUBaremetalResource", + "AsyncGPUBaremetalResource", + "GPUBaremetalResourceWithRawResponse", + "AsyncGPUBaremetalResourceWithRawResponse", + "GPUBaremetalResourceWithStreamingResponse", + "AsyncGPUBaremetalResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/gpu_baremetal/clusters/__init__.py b/src/gcore/resources/cloud/gpu_baremetal/clusters/__init__.py new file mode 100644 index 00000000..10acfe5d --- /dev/null +++ b/src/gcore/resources/cloud/gpu_baremetal/clusters/__init__.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .images import ( + ImagesResource, + AsyncImagesResource, + ImagesResourceWithRawResponse, + AsyncImagesResourceWithRawResponse, + ImagesResourceWithStreamingResponse, + AsyncImagesResourceWithStreamingResponse, +) +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from .servers import ( + ServersResource, + AsyncServersResource, + ServersResourceWithRawResponse, + AsyncServersResourceWithRawResponse, + ServersResourceWithStreamingResponse, + AsyncServersResourceWithStreamingResponse, +) +from .clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) +from .interfaces import ( + InterfacesResource, + AsyncInterfacesResource, + InterfacesResourceWithRawResponse, + AsyncInterfacesResourceWithRawResponse, + InterfacesResourceWithStreamingResponse, + AsyncInterfacesResourceWithStreamingResponse, +) + +__all__ = [ + "InterfacesResource", + "AsyncInterfacesResource", + "InterfacesResourceWithRawResponse", + "AsyncInterfacesResourceWithRawResponse", + "InterfacesResourceWithStreamingResponse", + "AsyncInterfacesResourceWithStreamingResponse", + "ServersResource", + "AsyncServersResource", + "ServersResourceWithRawResponse", + "AsyncServersResourceWithRawResponse", + "ServersResourceWithStreamingResponse", + "AsyncServersResourceWithStreamingResponse", + "FlavorsResource", + "AsyncFlavorsResource", + "FlavorsResourceWithRawResponse", + "AsyncFlavorsResourceWithRawResponse", + "FlavorsResourceWithStreamingResponse", + "AsyncFlavorsResourceWithStreamingResponse", + "ImagesResource", + "AsyncImagesResource", + "ImagesResourceWithRawResponse", + "AsyncImagesResourceWithRawResponse", + "ImagesResourceWithStreamingResponse", + "AsyncImagesResourceWithStreamingResponse", + "ClustersResource", + "AsyncClustersResource", + "ClustersResourceWithRawResponse", + "AsyncClustersResourceWithRawResponse", + "ClustersResourceWithStreamingResponse", + "AsyncClustersResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/gpu_baremetal/clusters/clusters.py b/src/gcore/resources/cloud/gpu_baremetal/clusters/clusters.py new file mode 100644 index 00000000..6de2b3c8 --- /dev/null +++ b/src/gcore/resources/cloud/gpu_baremetal/clusters/clusters.py @@ -0,0 +1,1375 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal + +import httpx + +from .images import ( + ImagesResource, + AsyncImagesResource, + ImagesResourceWithRawResponse, + AsyncImagesResourceWithRawResponse, + ImagesResourceWithStreamingResponse, + AsyncImagesResourceWithStreamingResponse, +) +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from .servers import ( + ServersResource, + AsyncServersResource, + ServersResourceWithRawResponse, + AsyncServersResourceWithRawResponse, + ServersResourceWithStreamingResponse, + AsyncServersResourceWithStreamingResponse, +) +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from .interfaces import ( + InterfacesResource, + AsyncInterfacesResource, + InterfacesResourceWithRawResponse, + AsyncInterfacesResourceWithRawResponse, + InterfacesResourceWithStreamingResponse, + AsyncInterfacesResourceWithStreamingResponse, +) +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .....pagination import SyncOffsetPage, AsyncOffsetPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.gpu_baremetal import ( + cluster_list_params, + cluster_action_params, + cluster_create_params, + cluster_delete_params, + cluster_resize_params, + cluster_rebuild_params, +) +from .....types.cloud.tag_update_map_param import TagUpdateMapParam +from .....types.cloud.gpu_baremetal.gpu_baremetal_cluster import GPUBaremetalCluster +from .....types.cloud.gpu_baremetal.clusters.gpu_baremetal_cluster_server_v1_list import GPUBaremetalClusterServerV1List + +__all__ = ["ClustersResource", "AsyncClustersResource"] + + +class ClustersResource(SyncAPIResource): + @cached_property + def interfaces(self) -> InterfacesResource: + return InterfacesResource(self._client) + + @cached_property + def servers(self) -> ServersResource: + return ServersResource(self._client) + + @cached_property + def flavors(self) -> FlavorsResource: + return FlavorsResource(self._client) + + @cached_property + def images(self) -> ImagesResource: + return ImagesResource(self._client) + + @cached_property + def with_raw_response(self) -> ClustersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ClustersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ClustersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ClustersResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor: str, + image_id: str, + name: str, + servers_count: int, + servers_settings: cluster_create_params.ServersSettings, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new bare metal GPU cluster with the specified configuration. + + Args: + project_id: Project ID + + region_id: Region ID + + flavor: Cluster flavor ID + + image_id: System image ID + + name: Cluster name + + servers_count: Number of servers in the cluster + + servers_settings: Configuration settings for the servers in the cluster + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters", + body=maybe_transform( + { + "flavor": flavor, + "image_id": image_id, + "name": name, + "servers_count": servers_count, + "servers_settings": servers_settings, + "tags": tags, + }, + cluster_create_params.ClusterCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + managed_by: List[Literal["k8s", "user"]] | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[GPUBaremetalCluster]: + """ + List all bare metal GPU clusters in the specified project and region. + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Limit of items on a single page + + managed_by: Specifies the entity responsible for managing the resource. + + - `user`: The resource (cluster) is created and maintained directly by the user. + - `k8s`: The resource is created and maintained automatically by Managed + Kubernetes service + + offset: Offset in results list + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters", + page=SyncOffsetPage[GPUBaremetalCluster], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "managed_by": managed_by, + "offset": offset, + }, + cluster_list_params.ClusterListParams, + ), + ), + model=GPUBaremetalCluster, + ) + + def delete( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + all_floating_ips: bool | Omit = omit, + all_reserved_fixed_ips: bool | Omit = omit, + floating_ip_ids: SequenceNotStr[str] | Omit = omit, + reserved_fixed_ip_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a bare metal GPU cluster and all its associated resources. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + all_floating_ips: Flag indicating whether the floating ips associated with server / cluster are + deleted + + all_reserved_fixed_ips: Flag indicating whether the reserved fixed ips associated with server / cluster + are deleted + + floating_ip_ids: Optional list of floating ips to be deleted + + reserved_fixed_ip_ids: Optional list of reserved fixed ips to be deleted + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._delete( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "all_floating_ips": all_floating_ips, + "all_reserved_fixed_ips": all_reserved_fixed_ips, + "floating_ip_ids": floating_ip_ids, + "reserved_fixed_ip_ids": reserved_fixed_ip_ids, + }, + cluster_delete_params.ClusterDeleteParams, + ), + ), + cast_to=TaskIDList, + ) + + def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["update_tags"], + tags: Optional[TagUpdateMapParam], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a baremetal GPU cluster. + + Available actions: update + tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._post( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}/action", + body=maybe_transform( + { + "action": action, + "tags": tags, + }, + cluster_action_params.ClusterActionParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUBaremetalCluster: + """ + Get detailed information about a specific bare metal GPU cluster. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._get( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUBaremetalCluster, + ) + + def powercycle_all_servers( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUBaremetalClusterServerV1List: + """ + Stops and then starts all cluster servers, effectively performing a hard reboot. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._post( + f"/cloud/v2/ai/clusters/{project_id}/{region_id}/{cluster_id}/powercycle", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUBaremetalClusterServerV1List, + ) + + def reboot_all_servers( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUBaremetalClusterServerV1List: + """ + Reboot all bare metal GPU cluster servers + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._post( + f"/cloud/v2/ai/clusters/{project_id}/{region_id}/{cluster_id}/reboot", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUBaremetalClusterServerV1List, + ) + + def rebuild( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + nodes: SequenceNotStr[str], + image_id: Optional[str] | Omit = omit, + user_data: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Rebuild one or more nodes in a GPU cluster. + + All cluster nodes must be specified + to update the cluster image. + + Args: + nodes: List of nodes uuids to be rebuild + + image_id: AI GPU image ID + + user_data: + String in base64 format.Examples of the `user_data`: + https://cloudinit.readthedocs.io/en/latest/topics/examples.html + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._post( + f"/cloud/v1/ai/clusters/gpu/{project_id}/{region_id}/{cluster_id}/rebuild", + body=maybe_transform( + { + "nodes": nodes, + "image_id": image_id, + "user_data": user_data, + }, + cluster_rebuild_params.ClusterRebuildParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def resize( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + instances_count: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Change the number of nodes in a GPU cluster. + + The cluster can be scaled up or + down. + + Args: + instances_count: Resized (total) number of instances + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._post( + f"/cloud/v1/ai/clusters/gpu/{project_id}/{region_id}/{cluster_id}/resize", + body=maybe_transform({"instances_count": instances_count}, cluster_resize_params.ClusterResizeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncClustersResource(AsyncAPIResource): + @cached_property + def interfaces(self) -> AsyncInterfacesResource: + return AsyncInterfacesResource(self._client) + + @cached_property + def servers(self) -> AsyncServersResource: + return AsyncServersResource(self._client) + + @cached_property + def flavors(self) -> AsyncFlavorsResource: + return AsyncFlavorsResource(self._client) + + @cached_property + def images(self) -> AsyncImagesResource: + return AsyncImagesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncClustersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncClustersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncClustersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncClustersResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor: str, + image_id: str, + name: str, + servers_count: int, + servers_settings: cluster_create_params.ServersSettings, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new bare metal GPU cluster with the specified configuration. + + Args: + project_id: Project ID + + region_id: Region ID + + flavor: Cluster flavor ID + + image_id: System image ID + + name: Cluster name + + servers_count: Number of servers in the cluster + + servers_settings: Configuration settings for the servers in the cluster + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters", + body=await async_maybe_transform( + { + "flavor": flavor, + "image_id": image_id, + "name": name, + "servers_count": servers_count, + "servers_settings": servers_settings, + "tags": tags, + }, + cluster_create_params.ClusterCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + managed_by: List[Literal["k8s", "user"]] | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[GPUBaremetalCluster, AsyncOffsetPage[GPUBaremetalCluster]]: + """ + List all bare metal GPU clusters in the specified project and region. + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Limit of items on a single page + + managed_by: Specifies the entity responsible for managing the resource. + + - `user`: The resource (cluster) is created and maintained directly by the user. + - `k8s`: The resource is created and maintained automatically by Managed + Kubernetes service + + offset: Offset in results list + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters", + page=AsyncOffsetPage[GPUBaremetalCluster], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "managed_by": managed_by, + "offset": offset, + }, + cluster_list_params.ClusterListParams, + ), + ), + model=GPUBaremetalCluster, + ) + + async def delete( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + all_floating_ips: bool | Omit = omit, + all_reserved_fixed_ips: bool | Omit = omit, + floating_ip_ids: SequenceNotStr[str] | Omit = omit, + reserved_fixed_ip_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a bare metal GPU cluster and all its associated resources. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + all_floating_ips: Flag indicating whether the floating ips associated with server / cluster are + deleted + + all_reserved_fixed_ips: Flag indicating whether the reserved fixed ips associated with server / cluster + are deleted + + floating_ip_ids: Optional list of floating ips to be deleted + + reserved_fixed_ip_ids: Optional list of reserved fixed ips to be deleted + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._delete( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "all_floating_ips": all_floating_ips, + "all_reserved_fixed_ips": all_reserved_fixed_ips, + "floating_ip_ids": floating_ip_ids, + "reserved_fixed_ip_ids": reserved_fixed_ip_ids, + }, + cluster_delete_params.ClusterDeleteParams, + ), + ), + cast_to=TaskIDList, + ) + + async def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["update_tags"], + tags: Optional[TagUpdateMapParam], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a baremetal GPU cluster. + + Available actions: update + tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._post( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}/action", + body=await async_maybe_transform( + { + "action": action, + "tags": tags, + }, + cluster_action_params.ClusterActionParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUBaremetalCluster: + """ + Get detailed information about a specific bare metal GPU cluster. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._get( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUBaremetalCluster, + ) + + async def powercycle_all_servers( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUBaremetalClusterServerV1List: + """ + Stops and then starts all cluster servers, effectively performing a hard reboot. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._post( + f"/cloud/v2/ai/clusters/{project_id}/{region_id}/{cluster_id}/powercycle", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUBaremetalClusterServerV1List, + ) + + async def reboot_all_servers( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUBaremetalClusterServerV1List: + """ + Reboot all bare metal GPU cluster servers + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._post( + f"/cloud/v2/ai/clusters/{project_id}/{region_id}/{cluster_id}/reboot", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUBaremetalClusterServerV1List, + ) + + async def rebuild( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + nodes: SequenceNotStr[str], + image_id: Optional[str] | Omit = omit, + user_data: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Rebuild one or more nodes in a GPU cluster. + + All cluster nodes must be specified + to update the cluster image. + + Args: + nodes: List of nodes uuids to be rebuild + + image_id: AI GPU image ID + + user_data: + String in base64 format.Examples of the `user_data`: + https://cloudinit.readthedocs.io/en/latest/topics/examples.html + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._post( + f"/cloud/v1/ai/clusters/gpu/{project_id}/{region_id}/{cluster_id}/rebuild", + body=await async_maybe_transform( + { + "nodes": nodes, + "image_id": image_id, + "user_data": user_data, + }, + cluster_rebuild_params.ClusterRebuildParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def resize( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + instances_count: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Change the number of nodes in a GPU cluster. + + The cluster can be scaled up or + down. + + Args: + instances_count: Resized (total) number of instances + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._post( + f"/cloud/v1/ai/clusters/gpu/{project_id}/{region_id}/{cluster_id}/resize", + body=await async_maybe_transform( + {"instances_count": instances_count}, cluster_resize_params.ClusterResizeParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class ClustersResourceWithRawResponse: + def __init__(self, clusters: ClustersResource) -> None: + self._clusters = clusters + + self.create = to_raw_response_wrapper( + clusters.create, + ) + self.list = to_raw_response_wrapper( + clusters.list, + ) + self.delete = to_raw_response_wrapper( + clusters.delete, + ) + self.action = to_raw_response_wrapper( + clusters.action, + ) + self.get = to_raw_response_wrapper( + clusters.get, + ) + self.powercycle_all_servers = to_raw_response_wrapper( + clusters.powercycle_all_servers, + ) + self.reboot_all_servers = to_raw_response_wrapper( + clusters.reboot_all_servers, + ) + self.rebuild = to_raw_response_wrapper( + clusters.rebuild, + ) + self.resize = to_raw_response_wrapper( + clusters.resize, + ) + + @cached_property + def interfaces(self) -> InterfacesResourceWithRawResponse: + return InterfacesResourceWithRawResponse(self._clusters.interfaces) + + @cached_property + def servers(self) -> ServersResourceWithRawResponse: + return ServersResourceWithRawResponse(self._clusters.servers) + + @cached_property + def flavors(self) -> FlavorsResourceWithRawResponse: + return FlavorsResourceWithRawResponse(self._clusters.flavors) + + @cached_property + def images(self) -> ImagesResourceWithRawResponse: + return ImagesResourceWithRawResponse(self._clusters.images) + + +class AsyncClustersResourceWithRawResponse: + def __init__(self, clusters: AsyncClustersResource) -> None: + self._clusters = clusters + + self.create = async_to_raw_response_wrapper( + clusters.create, + ) + self.list = async_to_raw_response_wrapper( + clusters.list, + ) + self.delete = async_to_raw_response_wrapper( + clusters.delete, + ) + self.action = async_to_raw_response_wrapper( + clusters.action, + ) + self.get = async_to_raw_response_wrapper( + clusters.get, + ) + self.powercycle_all_servers = async_to_raw_response_wrapper( + clusters.powercycle_all_servers, + ) + self.reboot_all_servers = async_to_raw_response_wrapper( + clusters.reboot_all_servers, + ) + self.rebuild = async_to_raw_response_wrapper( + clusters.rebuild, + ) + self.resize = async_to_raw_response_wrapper( + clusters.resize, + ) + + @cached_property + def interfaces(self) -> AsyncInterfacesResourceWithRawResponse: + return AsyncInterfacesResourceWithRawResponse(self._clusters.interfaces) + + @cached_property + def servers(self) -> AsyncServersResourceWithRawResponse: + return AsyncServersResourceWithRawResponse(self._clusters.servers) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithRawResponse: + return AsyncFlavorsResourceWithRawResponse(self._clusters.flavors) + + @cached_property + def images(self) -> AsyncImagesResourceWithRawResponse: + return AsyncImagesResourceWithRawResponse(self._clusters.images) + + +class ClustersResourceWithStreamingResponse: + def __init__(self, clusters: ClustersResource) -> None: + self._clusters = clusters + + self.create = to_streamed_response_wrapper( + clusters.create, + ) + self.list = to_streamed_response_wrapper( + clusters.list, + ) + self.delete = to_streamed_response_wrapper( + clusters.delete, + ) + self.action = to_streamed_response_wrapper( + clusters.action, + ) + self.get = to_streamed_response_wrapper( + clusters.get, + ) + self.powercycle_all_servers = to_streamed_response_wrapper( + clusters.powercycle_all_servers, + ) + self.reboot_all_servers = to_streamed_response_wrapper( + clusters.reboot_all_servers, + ) + self.rebuild = to_streamed_response_wrapper( + clusters.rebuild, + ) + self.resize = to_streamed_response_wrapper( + clusters.resize, + ) + + @cached_property + def interfaces(self) -> InterfacesResourceWithStreamingResponse: + return InterfacesResourceWithStreamingResponse(self._clusters.interfaces) + + @cached_property + def servers(self) -> ServersResourceWithStreamingResponse: + return ServersResourceWithStreamingResponse(self._clusters.servers) + + @cached_property + def flavors(self) -> FlavorsResourceWithStreamingResponse: + return FlavorsResourceWithStreamingResponse(self._clusters.flavors) + + @cached_property + def images(self) -> ImagesResourceWithStreamingResponse: + return ImagesResourceWithStreamingResponse(self._clusters.images) + + +class AsyncClustersResourceWithStreamingResponse: + def __init__(self, clusters: AsyncClustersResource) -> None: + self._clusters = clusters + + self.create = async_to_streamed_response_wrapper( + clusters.create, + ) + self.list = async_to_streamed_response_wrapper( + clusters.list, + ) + self.delete = async_to_streamed_response_wrapper( + clusters.delete, + ) + self.action = async_to_streamed_response_wrapper( + clusters.action, + ) + self.get = async_to_streamed_response_wrapper( + clusters.get, + ) + self.powercycle_all_servers = async_to_streamed_response_wrapper( + clusters.powercycle_all_servers, + ) + self.reboot_all_servers = async_to_streamed_response_wrapper( + clusters.reboot_all_servers, + ) + self.rebuild = async_to_streamed_response_wrapper( + clusters.rebuild, + ) + self.resize = async_to_streamed_response_wrapper( + clusters.resize, + ) + + @cached_property + def interfaces(self) -> AsyncInterfacesResourceWithStreamingResponse: + return AsyncInterfacesResourceWithStreamingResponse(self._clusters.interfaces) + + @cached_property + def servers(self) -> AsyncServersResourceWithStreamingResponse: + return AsyncServersResourceWithStreamingResponse(self._clusters.servers) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithStreamingResponse: + return AsyncFlavorsResourceWithStreamingResponse(self._clusters.flavors) + + @cached_property + def images(self) -> AsyncImagesResourceWithStreamingResponse: + return AsyncImagesResourceWithStreamingResponse(self._clusters.images) diff --git a/src/gcore/resources/cloud/gpu_baremetal/clusters/flavors.py b/src/gcore/resources/cloud/gpu_baremetal/clusters/flavors.py new file mode 100644 index 00000000..486250ea --- /dev/null +++ b/src/gcore/resources/cloud/gpu_baremetal/clusters/flavors.py @@ -0,0 +1,211 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.gpu_baremetal.clusters import flavor_list_params +from .....types.cloud.gpu_baremetal.clusters.gpu_baremetal_flavor_list import GPUBaremetalFlavorList + +__all__ = ["FlavorsResource", "AsyncFlavorsResource"] + + +class FlavorsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> FlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return FlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return FlavorsResourceWithStreamingResponse(self) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + hide_disabled: bool | Omit = omit, + include_prices: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUBaremetalFlavorList: + """ + List bare metal GPU flavors + + Args: + project_id: Project ID + + region_id: Region ID + + hide_disabled: Set to `true` to remove the disabled flavors from the response. + + include_prices: Set to `true` if the response should include flavor prices. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/flavors", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "hide_disabled": hide_disabled, + "include_prices": include_prices, + }, + flavor_list_params.FlavorListParams, + ), + ), + cast_to=GPUBaremetalFlavorList, + ) + + +class AsyncFlavorsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncFlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncFlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncFlavorsResourceWithStreamingResponse(self) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + hide_disabled: bool | Omit = omit, + include_prices: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUBaremetalFlavorList: + """ + List bare metal GPU flavors + + Args: + project_id: Project ID + + region_id: Region ID + + hide_disabled: Set to `true` to remove the disabled flavors from the response. + + include_prices: Set to `true` if the response should include flavor prices. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/flavors", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "hide_disabled": hide_disabled, + "include_prices": include_prices, + }, + flavor_list_params.FlavorListParams, + ), + ), + cast_to=GPUBaremetalFlavorList, + ) + + +class FlavorsResourceWithRawResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_raw_response_wrapper( + flavors.list, + ) + + +class AsyncFlavorsResourceWithRawResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_raw_response_wrapper( + flavors.list, + ) + + +class FlavorsResourceWithStreamingResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_streamed_response_wrapper( + flavors.list, + ) + + +class AsyncFlavorsResourceWithStreamingResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_streamed_response_wrapper( + flavors.list, + ) diff --git a/src/gcore/resources/cloud/gpu_baremetal/clusters/images.py b/src/gcore/resources/cloud/gpu_baremetal/clusters/images.py new file mode 100644 index 00000000..bd5f8291 --- /dev/null +++ b/src/gcore/resources/cloud/gpu_baremetal/clusters/images.py @@ -0,0 +1,582 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.gpu_image import GPUImage +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.gpu_image_list import GPUImageList +from .....types.cloud.gpu_baremetal.clusters import image_upload_params + +__all__ = ["ImagesResource", "AsyncImagesResource"] + + +class ImagesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ImagesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ImagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ImagesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ImagesResourceWithStreamingResponse(self) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUImageList: + """ + List bare metal GPU images + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/images", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUImageList, + ) + + def delete( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete bare metal GPU image + + Args: + project_id: Project ID + + region_id: Region ID + + image_id: Image ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return self._delete( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/images/{image_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUImage: + """ + Get bare metal GPU image + + Args: + project_id: Project ID + + region_id: Region ID + + image_id: Image ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return self._get( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/images/{image_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUImage, + ) + + def upload( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + url: str, + architecture: Optional[Literal["aarch64", "x86_64"]] | Omit = omit, + cow_format: bool | Omit = omit, + hw_firmware_type: Optional[Literal["bios", "uefi"]] | Omit = omit, + os_distro: Optional[str] | Omit = omit, + os_type: Optional[Literal["linux", "windows"]] | Omit = omit, + os_version: Optional[str] | Omit = omit, + ssh_key: Literal["allow", "deny", "required"] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Upload new bare metal GPU image + + Args: + project_id: Project ID + + region_id: Region ID + + name: Image name + + url: Image URL + + architecture: Image architecture type: aarch64, `x86_64` + + cow_format: When True, image cannot be deleted unless all volumes, created from it, are + deleted. + + hw_firmware_type: Specifies the type of firmware with which to boot the guest. + + os_distro: OS Distribution, i.e. Debian, CentOS, Ubuntu, CoreOS etc. + + os_type: The operating system installed on the image. Linux by default + + os_version: OS version, i.e. 19.04 (for Ubuntu) or 9.4 for Debian + + ssh_key: Permission to use a ssh key in instances + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/images", + body=maybe_transform( + { + "name": name, + "url": url, + "architecture": architecture, + "cow_format": cow_format, + "hw_firmware_type": hw_firmware_type, + "os_distro": os_distro, + "os_type": os_type, + "os_version": os_version, + "ssh_key": ssh_key, + "tags": tags, + }, + image_upload_params.ImageUploadParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncImagesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncImagesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncImagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncImagesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncImagesResourceWithStreamingResponse(self) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUImageList: + """ + List bare metal GPU images + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/images", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUImageList, + ) + + async def delete( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete bare metal GPU image + + Args: + project_id: Project ID + + region_id: Region ID + + image_id: Image ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return await self._delete( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/images/{image_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUImage: + """ + Get bare metal GPU image + + Args: + project_id: Project ID + + region_id: Region ID + + image_id: Image ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return await self._get( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/images/{image_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUImage, + ) + + async def upload( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + url: str, + architecture: Optional[Literal["aarch64", "x86_64"]] | Omit = omit, + cow_format: bool | Omit = omit, + hw_firmware_type: Optional[Literal["bios", "uefi"]] | Omit = omit, + os_distro: Optional[str] | Omit = omit, + os_type: Optional[Literal["linux", "windows"]] | Omit = omit, + os_version: Optional[str] | Omit = omit, + ssh_key: Literal["allow", "deny", "required"] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Upload new bare metal GPU image + + Args: + project_id: Project ID + + region_id: Region ID + + name: Image name + + url: Image URL + + architecture: Image architecture type: aarch64, `x86_64` + + cow_format: When True, image cannot be deleted unless all volumes, created from it, are + deleted. + + hw_firmware_type: Specifies the type of firmware with which to boot the guest. + + os_distro: OS Distribution, i.e. Debian, CentOS, Ubuntu, CoreOS etc. + + os_type: The operating system installed on the image. Linux by default + + os_version: OS version, i.e. 19.04 (for Ubuntu) or 9.4 for Debian + + ssh_key: Permission to use a ssh key in instances + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/images", + body=await async_maybe_transform( + { + "name": name, + "url": url, + "architecture": architecture, + "cow_format": cow_format, + "hw_firmware_type": hw_firmware_type, + "os_distro": os_distro, + "os_type": os_type, + "os_version": os_version, + "ssh_key": ssh_key, + "tags": tags, + }, + image_upload_params.ImageUploadParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class ImagesResourceWithRawResponse: + def __init__(self, images: ImagesResource) -> None: + self._images = images + + self.list = to_raw_response_wrapper( + images.list, + ) + self.delete = to_raw_response_wrapper( + images.delete, + ) + self.get = to_raw_response_wrapper( + images.get, + ) + self.upload = to_raw_response_wrapper( + images.upload, + ) + + +class AsyncImagesResourceWithRawResponse: + def __init__(self, images: AsyncImagesResource) -> None: + self._images = images + + self.list = async_to_raw_response_wrapper( + images.list, + ) + self.delete = async_to_raw_response_wrapper( + images.delete, + ) + self.get = async_to_raw_response_wrapper( + images.get, + ) + self.upload = async_to_raw_response_wrapper( + images.upload, + ) + + +class ImagesResourceWithStreamingResponse: + def __init__(self, images: ImagesResource) -> None: + self._images = images + + self.list = to_streamed_response_wrapper( + images.list, + ) + self.delete = to_streamed_response_wrapper( + images.delete, + ) + self.get = to_streamed_response_wrapper( + images.get, + ) + self.upload = to_streamed_response_wrapper( + images.upload, + ) + + +class AsyncImagesResourceWithStreamingResponse: + def __init__(self, images: AsyncImagesResource) -> None: + self._images = images + + self.list = async_to_streamed_response_wrapper( + images.list, + ) + self.delete = async_to_streamed_response_wrapper( + images.delete, + ) + self.get = async_to_streamed_response_wrapper( + images.get, + ) + self.upload = async_to_streamed_response_wrapper( + images.upload, + ) diff --git a/src/gcore/resources/cloud/gpu_baremetal/clusters/interfaces.py b/src/gcore/resources/cloud/gpu_baremetal/clusters/interfaces.py new file mode 100644 index 00000000..dcd6f5f0 --- /dev/null +++ b/src/gcore/resources/cloud/gpu_baremetal/clusters/interfaces.py @@ -0,0 +1,801 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, overload + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.gpu_baremetal.clusters import interface_attach_params, interface_detach_params +from .....types.cloud.network_interface_list import NetworkInterfaceList + +__all__ = ["InterfacesResource", "AsyncInterfacesResource"] + + +class InterfacesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> InterfacesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return InterfacesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InterfacesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return InterfacesResourceWithStreamingResponse(self) + + def list( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NetworkInterfaceList: + """ + Retrieve a list of network interfaces attached to the GPU cluster servers. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._get( + f"/cloud/v1/ai/clusters/{project_id}/{region_id}/{cluster_id}/interfaces", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NetworkInterfaceList, + ) + + @overload + def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ddos_profile: interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + ip_family: Literal["dual", "ipv4", "ipv6"] | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to bare metal GPU cluster server + + Args: + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + ip_family: Which subnets should be selected: IPv4, IPv6 or use dual stack. + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'external'. Union tag + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + subnet_id: str, + ddos_profile: interface_attach_params.NewInterfaceSpecificSubnetSchemaDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to bare metal GPU cluster server + + Args: + subnet_id: Port will get an IP address from this subnet + + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'subnet' + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + network_id: str, + ddos_profile: interface_attach_params.NewInterfaceAnySubnetSchemaDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + ip_family: Literal["dual", "ipv4", "ipv6"] | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceAnySubnetSchemaSecurityGroup] | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to bare metal GPU cluster server + + Args: + network_id: Port will get an IP address in this network subnet + + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + ip_family: Which subnets should be selected: IPv4, IPv6 or use dual stack. + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'any_subnet' + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + port_id: str, + ddos_profile: interface_attach_params.NewInterfaceReservedFixedIPSchemaDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to bare metal GPU cluster server + + Args: + port_id: Port ID + + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'reserved_fixed_ip'. Union tag + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ddos_profile: interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile + | interface_attach_params.NewInterfaceSpecificSubnetSchemaDDOSProfile + | interface_attach_params.NewInterfaceAnySubnetSchemaDDOSProfile + | interface_attach_params.NewInterfaceReservedFixedIPSchemaDDOSProfile + | Omit = omit, + interface_name: str | Omit = omit, + ip_family: Literal["dual", "ipv4", "ipv6"] | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceAnySubnetSchemaSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] + | Omit = omit, + type: str | Omit = omit, + subnet_id: str | Omit = omit, + network_id: str | Omit = omit, + port_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._post( + f"/cloud/v1/ai/clusters/{project_id}/{region_id}/{instance_id}/attach_interface", + body=maybe_transform( + { + "ddos_profile": ddos_profile, + "interface_name": interface_name, + "ip_family": ip_family, + "port_group": port_group, + "security_groups": security_groups, + "type": type, + "subnet_id": subnet_id, + "network_id": network_id, + "port_id": port_id, + }, + interface_attach_params.InterfaceAttachParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def detach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ip_address: str, + port_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Detach interface from bare metal GPU cluster server + + Args: + ip_address: IP address + + port_id: ID of the port + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._post( + f"/cloud/v1/ai/clusters/{project_id}/{region_id}/{instance_id}/detach_interface", + body=maybe_transform( + { + "ip_address": ip_address, + "port_id": port_id, + }, + interface_detach_params.InterfaceDetachParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncInterfacesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncInterfacesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncInterfacesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInterfacesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncInterfacesResourceWithStreamingResponse(self) + + async def list( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NetworkInterfaceList: + """ + Retrieve a list of network interfaces attached to the GPU cluster servers. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._get( + f"/cloud/v1/ai/clusters/{project_id}/{region_id}/{cluster_id}/interfaces", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NetworkInterfaceList, + ) + + @overload + async def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ddos_profile: interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + ip_family: Literal["dual", "ipv4", "ipv6"] | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to bare metal GPU cluster server + + Args: + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + ip_family: Which subnets should be selected: IPv4, IPv6 or use dual stack. + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'external'. Union tag + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + subnet_id: str, + ddos_profile: interface_attach_params.NewInterfaceSpecificSubnetSchemaDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to bare metal GPU cluster server + + Args: + subnet_id: Port will get an IP address from this subnet + + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'subnet' + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + network_id: str, + ddos_profile: interface_attach_params.NewInterfaceAnySubnetSchemaDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + ip_family: Literal["dual", "ipv4", "ipv6"] | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceAnySubnetSchemaSecurityGroup] | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to bare metal GPU cluster server + + Args: + network_id: Port will get an IP address in this network subnet + + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + ip_family: Which subnets should be selected: IPv4, IPv6 or use dual stack. + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'any_subnet' + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + port_id: str, + ddos_profile: interface_attach_params.NewInterfaceReservedFixedIPSchemaDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to bare metal GPU cluster server + + Args: + port_id: Port ID + + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'reserved_fixed_ip'. Union tag + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + async def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ddos_profile: interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile + | interface_attach_params.NewInterfaceSpecificSubnetSchemaDDOSProfile + | interface_attach_params.NewInterfaceAnySubnetSchemaDDOSProfile + | interface_attach_params.NewInterfaceReservedFixedIPSchemaDDOSProfile + | Omit = omit, + interface_name: str | Omit = omit, + ip_family: Literal["dual", "ipv4", "ipv6"] | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceAnySubnetSchemaSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] + | Omit = omit, + type: str | Omit = omit, + subnet_id: str | Omit = omit, + network_id: str | Omit = omit, + port_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._post( + f"/cloud/v1/ai/clusters/{project_id}/{region_id}/{instance_id}/attach_interface", + body=await async_maybe_transform( + { + "ddos_profile": ddos_profile, + "interface_name": interface_name, + "ip_family": ip_family, + "port_group": port_group, + "security_groups": security_groups, + "type": type, + "subnet_id": subnet_id, + "network_id": network_id, + "port_id": port_id, + }, + interface_attach_params.InterfaceAttachParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def detach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ip_address: str, + port_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Detach interface from bare metal GPU cluster server + + Args: + ip_address: IP address + + port_id: ID of the port + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._post( + f"/cloud/v1/ai/clusters/{project_id}/{region_id}/{instance_id}/detach_interface", + body=await async_maybe_transform( + { + "ip_address": ip_address, + "port_id": port_id, + }, + interface_detach_params.InterfaceDetachParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class InterfacesResourceWithRawResponse: + def __init__(self, interfaces: InterfacesResource) -> None: + self._interfaces = interfaces + + self.list = to_raw_response_wrapper( + interfaces.list, + ) + self.attach = to_raw_response_wrapper( + interfaces.attach, + ) + self.detach = to_raw_response_wrapper( + interfaces.detach, + ) + + +class AsyncInterfacesResourceWithRawResponse: + def __init__(self, interfaces: AsyncInterfacesResource) -> None: + self._interfaces = interfaces + + self.list = async_to_raw_response_wrapper( + interfaces.list, + ) + self.attach = async_to_raw_response_wrapper( + interfaces.attach, + ) + self.detach = async_to_raw_response_wrapper( + interfaces.detach, + ) + + +class InterfacesResourceWithStreamingResponse: + def __init__(self, interfaces: InterfacesResource) -> None: + self._interfaces = interfaces + + self.list = to_streamed_response_wrapper( + interfaces.list, + ) + self.attach = to_streamed_response_wrapper( + interfaces.attach, + ) + self.detach = to_streamed_response_wrapper( + interfaces.detach, + ) + + +class AsyncInterfacesResourceWithStreamingResponse: + def __init__(self, interfaces: AsyncInterfacesResource) -> None: + self._interfaces = interfaces + + self.list = async_to_streamed_response_wrapper( + interfaces.list, + ) + self.attach = async_to_streamed_response_wrapper( + interfaces.attach, + ) + self.detach = async_to_streamed_response_wrapper( + interfaces.detach, + ) diff --git a/src/gcore/resources/cloud/gpu_baremetal/clusters/servers.py b/src/gcore/resources/cloud/gpu_baremetal/clusters/servers.py new file mode 100644 index 00000000..36f89dd7 --- /dev/null +++ b/src/gcore/resources/cloud/gpu_baremetal/clusters/servers.py @@ -0,0 +1,723 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .....pagination import SyncOffsetPage, AsyncOffsetPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.cloud.console import Console +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.gpu_baremetal.clusters import server_list_params, server_delete_params +from .....types.cloud.gpu_baremetal.clusters.gpu_baremetal_cluster_server import GPUBaremetalClusterServer +from .....types.cloud.gpu_baremetal.clusters.gpu_baremetal_cluster_server_v1 import GPUBaremetalClusterServerV1 + +__all__ = ["ServersResource", "AsyncServersResource"] + + +class ServersResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ServersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ServersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ServersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ServersResourceWithStreamingResponse(self) + + def list( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + changed_before: Union[str, datetime] | Omit = omit, + changed_since: Union[str, datetime] | Omit = omit, + ip_address: str | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["created_at.asc", "created_at.desc", "status.asc", "status.desc"] | Omit = omit, + status: Literal[ + "ACTIVE", + "BUILD", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PAUSED", + "REBOOT", + "REBUILD", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "VERIFY_RESIZE", + ] + | Omit = omit, + uuids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[GPUBaremetalClusterServer]: + """List all servers in a bare metal GPU cluster. + + Results can be filtered and + paginated. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + changed_before: Filters the results to include only servers whose last change timestamp is less + than the specified datetime. Format: ISO 8601. + + changed_since: Filters the results to include only servers whose last change timestamp is + greater than or equal to the specified datetime. Format: ISO 8601. + + ip_address: Filter servers by ip address. + + limit: Limit of items on a single page + + name: Filter servers by name. You can provide a full or partial name, servers with + matching names will be returned. For example, entering 'test' will return all + servers that contain 'test' in their name. + + offset: Offset in results list + + order_by: Order field + + status: Filters servers by status. + + uuids: Filter servers by uuid. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._get_api_list( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}/servers", + page=SyncOffsetPage[GPUBaremetalClusterServer], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "changed_before": changed_before, + "changed_since": changed_since, + "ip_address": ip_address, + "limit": limit, + "name": name, + "offset": offset, + "order_by": order_by, + "status": status, + "uuids": uuids, + }, + server_list_params.ServerListParams, + ), + ), + model=GPUBaremetalClusterServer, + ) + + def delete( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_id: str, + delete_floatings: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Delete a specific node from a GPU cluster. + + The node must be in a state that + allows deletion. + + Args: + delete_floatings: Set False if you do not want to delete assigned floating IPs. By default, it's + True. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._delete( + f"/cloud/v1/ai/clusters/gpu/{project_id}/{region_id}/{cluster_id}/node/{instance_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"delete_floatings": delete_floatings}, server_delete_params.ServerDeleteParams), + ), + cast_to=TaskIDList, + ) + + def get_console( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Console: + """ + Get bare metal GPU cluster server console URL + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._get( + f"/cloud/v1/ai/clusters/{project_id}/{region_id}/{instance_id}/get_console", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Console, + ) + + def powercycle( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUBaremetalClusterServerV1: + """ + Stops and then starts the server, effectively performing a hard reboot. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._post( + f"/cloud/v1/ai/clusters/{project_id}/{region_id}/{instance_id}/powercycle", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUBaremetalClusterServerV1, + ) + + def reboot( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUBaremetalClusterServerV1: + """ + Reboot one bare metal GPU cluster server + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._post( + f"/cloud/v1/ai/clusters/{project_id}/{region_id}/{instance_id}/reboot", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUBaremetalClusterServerV1, + ) + + +class AsyncServersResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncServersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncServersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncServersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncServersResourceWithStreamingResponse(self) + + def list( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + changed_before: Union[str, datetime] | Omit = omit, + changed_since: Union[str, datetime] | Omit = omit, + ip_address: str | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["created_at.asc", "created_at.desc", "status.asc", "status.desc"] | Omit = omit, + status: Literal[ + "ACTIVE", + "BUILD", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PAUSED", + "REBOOT", + "REBUILD", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "VERIFY_RESIZE", + ] + | Omit = omit, + uuids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[GPUBaremetalClusterServer, AsyncOffsetPage[GPUBaremetalClusterServer]]: + """List all servers in a bare metal GPU cluster. + + Results can be filtered and + paginated. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + changed_before: Filters the results to include only servers whose last change timestamp is less + than the specified datetime. Format: ISO 8601. + + changed_since: Filters the results to include only servers whose last change timestamp is + greater than or equal to the specified datetime. Format: ISO 8601. + + ip_address: Filter servers by ip address. + + limit: Limit of items on a single page + + name: Filter servers by name. You can provide a full or partial name, servers with + matching names will be returned. For example, entering 'test' will return all + servers that contain 'test' in their name. + + offset: Offset in results list + + order_by: Order field + + status: Filters servers by status. + + uuids: Filter servers by uuid. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._get_api_list( + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}/servers", + page=AsyncOffsetPage[GPUBaremetalClusterServer], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "changed_before": changed_before, + "changed_since": changed_since, + "ip_address": ip_address, + "limit": limit, + "name": name, + "offset": offset, + "order_by": order_by, + "status": status, + "uuids": uuids, + }, + server_list_params.ServerListParams, + ), + ), + model=GPUBaremetalClusterServer, + ) + + async def delete( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_id: str, + delete_floatings: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Delete a specific node from a GPU cluster. + + The node must be in a state that + allows deletion. + + Args: + delete_floatings: Set False if you do not want to delete assigned floating IPs. By default, it's + True. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._delete( + f"/cloud/v1/ai/clusters/gpu/{project_id}/{region_id}/{cluster_id}/node/{instance_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"delete_floatings": delete_floatings}, server_delete_params.ServerDeleteParams + ), + ), + cast_to=TaskIDList, + ) + + async def get_console( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Console: + """ + Get bare metal GPU cluster server console URL + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._get( + f"/cloud/v1/ai/clusters/{project_id}/{region_id}/{instance_id}/get_console", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Console, + ) + + async def powercycle( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUBaremetalClusterServerV1: + """ + Stops and then starts the server, effectively performing a hard reboot. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._post( + f"/cloud/v1/ai/clusters/{project_id}/{region_id}/{instance_id}/powercycle", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUBaremetalClusterServerV1, + ) + + async def reboot( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUBaremetalClusterServerV1: + """ + Reboot one bare metal GPU cluster server + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._post( + f"/cloud/v1/ai/clusters/{project_id}/{region_id}/{instance_id}/reboot", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUBaremetalClusterServerV1, + ) + + +class ServersResourceWithRawResponse: + def __init__(self, servers: ServersResource) -> None: + self._servers = servers + + self.list = to_raw_response_wrapper( + servers.list, + ) + self.delete = to_raw_response_wrapper( + servers.delete, + ) + self.get_console = to_raw_response_wrapper( + servers.get_console, + ) + self.powercycle = to_raw_response_wrapper( + servers.powercycle, + ) + self.reboot = to_raw_response_wrapper( + servers.reboot, + ) + + +class AsyncServersResourceWithRawResponse: + def __init__(self, servers: AsyncServersResource) -> None: + self._servers = servers + + self.list = async_to_raw_response_wrapper( + servers.list, + ) + self.delete = async_to_raw_response_wrapper( + servers.delete, + ) + self.get_console = async_to_raw_response_wrapper( + servers.get_console, + ) + self.powercycle = async_to_raw_response_wrapper( + servers.powercycle, + ) + self.reboot = async_to_raw_response_wrapper( + servers.reboot, + ) + + +class ServersResourceWithStreamingResponse: + def __init__(self, servers: ServersResource) -> None: + self._servers = servers + + self.list = to_streamed_response_wrapper( + servers.list, + ) + self.delete = to_streamed_response_wrapper( + servers.delete, + ) + self.get_console = to_streamed_response_wrapper( + servers.get_console, + ) + self.powercycle = to_streamed_response_wrapper( + servers.powercycle, + ) + self.reboot = to_streamed_response_wrapper( + servers.reboot, + ) + + +class AsyncServersResourceWithStreamingResponse: + def __init__(self, servers: AsyncServersResource) -> None: + self._servers = servers + + self.list = async_to_streamed_response_wrapper( + servers.list, + ) + self.delete = async_to_streamed_response_wrapper( + servers.delete, + ) + self.get_console = async_to_streamed_response_wrapper( + servers.get_console, + ) + self.powercycle = async_to_streamed_response_wrapper( + servers.powercycle, + ) + self.reboot = async_to_streamed_response_wrapper( + servers.reboot, + ) diff --git a/src/gcore/resources/cloud/gpu_baremetal/gpu_baremetal.py b/src/gcore/resources/cloud/gpu_baremetal/gpu_baremetal.py new file mode 100644 index 00000000..b752dffd --- /dev/null +++ b/src/gcore/resources/cloud/gpu_baremetal/gpu_baremetal.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from .clusters.clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) + +__all__ = ["GPUBaremetalResource", "AsyncGPUBaremetalResource"] + + +class GPUBaremetalResource(SyncAPIResource): + @cached_property + def clusters(self) -> ClustersResource: + return ClustersResource(self._client) + + @cached_property + def with_raw_response(self) -> GPUBaremetalResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return GPUBaremetalResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> GPUBaremetalResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return GPUBaremetalResourceWithStreamingResponse(self) + + +class AsyncGPUBaremetalResource(AsyncAPIResource): + @cached_property + def clusters(self) -> AsyncClustersResource: + return AsyncClustersResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncGPUBaremetalResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncGPUBaremetalResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncGPUBaremetalResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncGPUBaremetalResourceWithStreamingResponse(self) + + +class GPUBaremetalResourceWithRawResponse: + def __init__(self, gpu_baremetal: GPUBaremetalResource) -> None: + self._gpu_baremetal = gpu_baremetal + + @cached_property + def clusters(self) -> ClustersResourceWithRawResponse: + return ClustersResourceWithRawResponse(self._gpu_baremetal.clusters) + + +class AsyncGPUBaremetalResourceWithRawResponse: + def __init__(self, gpu_baremetal: AsyncGPUBaremetalResource) -> None: + self._gpu_baremetal = gpu_baremetal + + @cached_property + def clusters(self) -> AsyncClustersResourceWithRawResponse: + return AsyncClustersResourceWithRawResponse(self._gpu_baremetal.clusters) + + +class GPUBaremetalResourceWithStreamingResponse: + def __init__(self, gpu_baremetal: GPUBaremetalResource) -> None: + self._gpu_baremetal = gpu_baremetal + + @cached_property + def clusters(self) -> ClustersResourceWithStreamingResponse: + return ClustersResourceWithStreamingResponse(self._gpu_baremetal.clusters) + + +class AsyncGPUBaremetalResourceWithStreamingResponse: + def __init__(self, gpu_baremetal: AsyncGPUBaremetalResource) -> None: + self._gpu_baremetal = gpu_baremetal + + @cached_property + def clusters(self) -> AsyncClustersResourceWithStreamingResponse: + return AsyncClustersResourceWithStreamingResponse(self._gpu_baremetal.clusters) diff --git a/src/gcore/resources/cloud/gpu_virtual/__init__.py b/src/gcore/resources/cloud/gpu_virtual/__init__.py new file mode 100644 index 00000000..214d9c94 --- /dev/null +++ b/src/gcore/resources/cloud/gpu_virtual/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) +from .gpu_virtual import ( + GPUVirtualResource, + AsyncGPUVirtualResource, + GPUVirtualResourceWithRawResponse, + AsyncGPUVirtualResourceWithRawResponse, + GPUVirtualResourceWithStreamingResponse, + AsyncGPUVirtualResourceWithStreamingResponse, +) + +__all__ = [ + "ClustersResource", + "AsyncClustersResource", + "ClustersResourceWithRawResponse", + "AsyncClustersResourceWithRawResponse", + "ClustersResourceWithStreamingResponse", + "AsyncClustersResourceWithStreamingResponse", + "GPUVirtualResource", + "AsyncGPUVirtualResource", + "GPUVirtualResourceWithRawResponse", + "AsyncGPUVirtualResourceWithRawResponse", + "GPUVirtualResourceWithStreamingResponse", + "AsyncGPUVirtualResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/gpu_virtual/clusters/__init__.py b/src/gcore/resources/cloud/gpu_virtual/clusters/__init__.py new file mode 100644 index 00000000..567fb0f3 --- /dev/null +++ b/src/gcore/resources/cloud/gpu_virtual/clusters/__init__.py @@ -0,0 +1,89 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .images import ( + ImagesResource, + AsyncImagesResource, + ImagesResourceWithRawResponse, + AsyncImagesResourceWithRawResponse, + ImagesResourceWithStreamingResponse, + AsyncImagesResourceWithStreamingResponse, +) +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from .servers import ( + ServersResource, + AsyncServersResource, + ServersResourceWithRawResponse, + AsyncServersResourceWithRawResponse, + ServersResourceWithStreamingResponse, + AsyncServersResourceWithStreamingResponse, +) +from .volumes import ( + VolumesResource, + AsyncVolumesResource, + VolumesResourceWithRawResponse, + AsyncVolumesResourceWithRawResponse, + VolumesResourceWithStreamingResponse, + AsyncVolumesResourceWithStreamingResponse, +) +from .clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) +from .interfaces import ( + InterfacesResource, + AsyncInterfacesResource, + InterfacesResourceWithRawResponse, + AsyncInterfacesResourceWithRawResponse, + InterfacesResourceWithStreamingResponse, + AsyncInterfacesResourceWithStreamingResponse, +) + +__all__ = [ + "ServersResource", + "AsyncServersResource", + "ServersResourceWithRawResponse", + "AsyncServersResourceWithRawResponse", + "ServersResourceWithStreamingResponse", + "AsyncServersResourceWithStreamingResponse", + "VolumesResource", + "AsyncVolumesResource", + "VolumesResourceWithRawResponse", + "AsyncVolumesResourceWithRawResponse", + "VolumesResourceWithStreamingResponse", + "AsyncVolumesResourceWithStreamingResponse", + "InterfacesResource", + "AsyncInterfacesResource", + "InterfacesResourceWithRawResponse", + "AsyncInterfacesResourceWithRawResponse", + "InterfacesResourceWithStreamingResponse", + "AsyncInterfacesResourceWithStreamingResponse", + "FlavorsResource", + "AsyncFlavorsResource", + "FlavorsResourceWithRawResponse", + "AsyncFlavorsResourceWithRawResponse", + "FlavorsResourceWithStreamingResponse", + "AsyncFlavorsResourceWithStreamingResponse", + "ImagesResource", + "AsyncImagesResource", + "ImagesResourceWithRawResponse", + "AsyncImagesResourceWithRawResponse", + "ImagesResourceWithStreamingResponse", + "AsyncImagesResourceWithStreamingResponse", + "ClustersResource", + "AsyncClustersResource", + "ClustersResourceWithRawResponse", + "AsyncClustersResourceWithRawResponse", + "ClustersResourceWithStreamingResponse", + "AsyncClustersResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/gpu_virtual/clusters/clusters.py b/src/gcore/resources/cloud/gpu_virtual/clusters/clusters.py new file mode 100644 index 00000000..8fe0de91 --- /dev/null +++ b/src/gcore/resources/cloud/gpu_virtual/clusters/clusters.py @@ -0,0 +1,1539 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, overload + +import httpx + +from .images import ( + ImagesResource, + AsyncImagesResource, + ImagesResourceWithRawResponse, + AsyncImagesResourceWithRawResponse, + ImagesResourceWithStreamingResponse, + AsyncImagesResourceWithStreamingResponse, +) +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from .servers import ( + ServersResource, + AsyncServersResource, + ServersResourceWithRawResponse, + AsyncServersResourceWithRawResponse, + ServersResourceWithStreamingResponse, + AsyncServersResourceWithStreamingResponse, +) +from .volumes import ( + VolumesResource, + AsyncVolumesResource, + VolumesResourceWithRawResponse, + AsyncVolumesResourceWithRawResponse, + VolumesResourceWithStreamingResponse, + AsyncVolumesResourceWithStreamingResponse, +) +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ....._utils import required_args, maybe_transform, async_maybe_transform +from .interfaces import ( + InterfacesResource, + AsyncInterfacesResource, + InterfacesResourceWithRawResponse, + AsyncInterfacesResourceWithRawResponse, + InterfacesResourceWithStreamingResponse, + AsyncInterfacesResourceWithStreamingResponse, +) +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .....pagination import SyncOffsetPage, AsyncOffsetPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.cloud.gpu_virtual import ( + cluster_list_params, + cluster_action_params, + cluster_create_params, + cluster_delete_params, + cluster_update_params, +) +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.tag_update_map_param import TagUpdateMapParam +from .....types.cloud.gpu_virtual.gpu_virtual_cluster import GPUVirtualCluster + +__all__ = ["ClustersResource", "AsyncClustersResource"] + + +class ClustersResource(SyncAPIResource): + @cached_property + def servers(self) -> ServersResource: + return ServersResource(self._client) + + @cached_property + def volumes(self) -> VolumesResource: + return VolumesResource(self._client) + + @cached_property + def interfaces(self) -> InterfacesResource: + return InterfacesResource(self._client) + + @cached_property + def flavors(self) -> FlavorsResource: + return FlavorsResource(self._client) + + @cached_property + def images(self) -> ImagesResource: + return ImagesResource(self._client) + + @cached_property + def with_raw_response(self) -> ClustersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ClustersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ClustersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ClustersResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor: str, + name: str, + servers_count: int, + servers_settings: cluster_create_params.ServersSettings, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new virtual GPU cluster with the specified configuration. + + Args: + project_id: Project ID + + region_id: Region ID + + flavor: Cluster flavor ID + + name: Cluster name + + servers_count: Number of servers in the cluster + + servers_settings: Configuration settings for the servers in the cluster + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters", + body=maybe_transform( + { + "flavor": flavor, + "name": name, + "servers_count": servers_count, + "servers_settings": servers_settings, + "tags": tags, + }, + cluster_create_params.ClusterCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUVirtualCluster: + """ + Update the name of an existing virtual GPU cluster. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + name: Cluster name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._patch( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}", + body=maybe_transform({"name": name}, cluster_update_params.ClusterUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUVirtualCluster, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[GPUVirtualCluster]: + """ + List all virtual GPU clusters in the specified project and region. + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Limit of items on a single page + + offset: Offset in results list + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters", + page=SyncOffsetPage[GPUVirtualCluster], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + cluster_list_params.ClusterListParams, + ), + ), + model=GPUVirtualCluster, + ) + + def delete( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + all_floating_ips: bool | Omit = omit, + all_reserved_fixed_ips: bool | Omit = omit, + all_volumes: bool | Omit = omit, + floating_ip_ids: SequenceNotStr[str] | Omit = omit, + reserved_fixed_ip_ids: SequenceNotStr[str] | Omit = omit, + volume_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a virtual GPU cluster and all its associated resources. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + all_floating_ips: Flag indicating whether the floating ips associated with server / cluster are + deleted + + all_reserved_fixed_ips: Flag indicating whether the reserved fixed ips associated with server / cluster + are deleted + + all_volumes: Flag indicating whether all attached volumes are deleted + + floating_ip_ids: Optional list of floating ips to be deleted + + reserved_fixed_ip_ids: Optional list of reserved fixed ips to be deleted + + volume_ids: Optional list of volumes to be deleted + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._delete( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "all_floating_ips": all_floating_ips, + "all_reserved_fixed_ips": all_reserved_fixed_ips, + "all_volumes": all_volumes, + "floating_ip_ids": floating_ip_ids, + "reserved_fixed_ip_ids": reserved_fixed_ip_ids, + "volume_ids": volume_ids, + }, + cluster_delete_params.ClusterDeleteParams, + ), + ), + cast_to=TaskIDList, + ) + + @overload + def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["start"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a virtual GPU cluster. + + Available actions: start, + stop, soft reboot, hard reboot, resize, update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["stop"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a virtual GPU cluster. + + Available actions: start, + stop, soft reboot, hard reboot, resize, update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["soft_reboot"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a virtual GPU cluster. + + Available actions: start, + stop, soft reboot, hard reboot, resize, update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["hard_reboot"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a virtual GPU cluster. + + Available actions: start, + stop, soft reboot, hard reboot, resize, update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["update_tags"], + tags: Optional[TagUpdateMapParam], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a virtual GPU cluster. + + Available actions: start, + stop, soft reboot, hard reboot, resize, update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["resize"], + servers_count: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a virtual GPU cluster. + + Available actions: start, + stop, soft reboot, hard reboot, resize, update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + servers_count: Requested servers count + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["action"], ["action", "tags"], ["action", "servers_count"]) + def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["start"] + | Literal["stop"] + | Literal["soft_reboot"] + | Literal["hard_reboot"] + | Literal["update_tags"] + | Literal["resize"], + tags: Optional[TagUpdateMapParam] | Omit = omit, + servers_count: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._post( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/action", + body=maybe_transform( + { + "action": action, + "tags": tags, + "servers_count": servers_count, + }, + cluster_action_params.ClusterActionParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUVirtualCluster: + """ + Get detailed information about a specific virtual GPU cluster. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUVirtualCluster, + ) + + +class AsyncClustersResource(AsyncAPIResource): + @cached_property + def servers(self) -> AsyncServersResource: + return AsyncServersResource(self._client) + + @cached_property + def volumes(self) -> AsyncVolumesResource: + return AsyncVolumesResource(self._client) + + @cached_property + def interfaces(self) -> AsyncInterfacesResource: + return AsyncInterfacesResource(self._client) + + @cached_property + def flavors(self) -> AsyncFlavorsResource: + return AsyncFlavorsResource(self._client) + + @cached_property + def images(self) -> AsyncImagesResource: + return AsyncImagesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncClustersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncClustersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncClustersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncClustersResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor: str, + name: str, + servers_count: int, + servers_settings: cluster_create_params.ServersSettings, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new virtual GPU cluster with the specified configuration. + + Args: + project_id: Project ID + + region_id: Region ID + + flavor: Cluster flavor ID + + name: Cluster name + + servers_count: Number of servers in the cluster + + servers_settings: Configuration settings for the servers in the cluster + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters", + body=await async_maybe_transform( + { + "flavor": flavor, + "name": name, + "servers_count": servers_count, + "servers_settings": servers_settings, + "tags": tags, + }, + cluster_create_params.ClusterCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUVirtualCluster: + """ + Update the name of an existing virtual GPU cluster. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + name: Cluster name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._patch( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}", + body=await async_maybe_transform({"name": name}, cluster_update_params.ClusterUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUVirtualCluster, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[GPUVirtualCluster, AsyncOffsetPage[GPUVirtualCluster]]: + """ + List all virtual GPU clusters in the specified project and region. + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Limit of items on a single page + + offset: Offset in results list + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters", + page=AsyncOffsetPage[GPUVirtualCluster], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + cluster_list_params.ClusterListParams, + ), + ), + model=GPUVirtualCluster, + ) + + async def delete( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + all_floating_ips: bool | Omit = omit, + all_reserved_fixed_ips: bool | Omit = omit, + all_volumes: bool | Omit = omit, + floating_ip_ids: SequenceNotStr[str] | Omit = omit, + reserved_fixed_ip_ids: SequenceNotStr[str] | Omit = omit, + volume_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a virtual GPU cluster and all its associated resources. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + all_floating_ips: Flag indicating whether the floating ips associated with server / cluster are + deleted + + all_reserved_fixed_ips: Flag indicating whether the reserved fixed ips associated with server / cluster + are deleted + + all_volumes: Flag indicating whether all attached volumes are deleted + + floating_ip_ids: Optional list of floating ips to be deleted + + reserved_fixed_ip_ids: Optional list of reserved fixed ips to be deleted + + volume_ids: Optional list of volumes to be deleted + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._delete( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "all_floating_ips": all_floating_ips, + "all_reserved_fixed_ips": all_reserved_fixed_ips, + "all_volumes": all_volumes, + "floating_ip_ids": floating_ip_ids, + "reserved_fixed_ip_ids": reserved_fixed_ip_ids, + "volume_ids": volume_ids, + }, + cluster_delete_params.ClusterDeleteParams, + ), + ), + cast_to=TaskIDList, + ) + + @overload + async def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["start"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a virtual GPU cluster. + + Available actions: start, + stop, soft reboot, hard reboot, resize, update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["stop"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a virtual GPU cluster. + + Available actions: start, + stop, soft reboot, hard reboot, resize, update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["soft_reboot"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a virtual GPU cluster. + + Available actions: start, + stop, soft reboot, hard reboot, resize, update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["hard_reboot"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a virtual GPU cluster. + + Available actions: start, + stop, soft reboot, hard reboot, resize, update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["update_tags"], + tags: Optional[TagUpdateMapParam], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a virtual GPU cluster. + + Available actions: start, + stop, soft reboot, hard reboot, resize, update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["resize"], + servers_count: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Perform a specific action on a virtual GPU cluster. + + Available actions: start, + stop, soft reboot, hard reboot, resize, update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + action: Action name + + servers_count: Requested servers count + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["action"], ["action", "tags"], ["action", "servers_count"]) + async def action( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["start"] + | Literal["stop"] + | Literal["soft_reboot"] + | Literal["hard_reboot"] + | Literal["update_tags"] + | Literal["resize"], + tags: Optional[TagUpdateMapParam] | Omit = omit, + servers_count: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._post( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/action", + body=await async_maybe_transform( + { + "action": action, + "tags": tags, + "servers_count": servers_count, + }, + cluster_action_params.ClusterActionParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUVirtualCluster: + """ + Get detailed information about a specific virtual GPU cluster. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUVirtualCluster, + ) + + +class ClustersResourceWithRawResponse: + def __init__(self, clusters: ClustersResource) -> None: + self._clusters = clusters + + self.create = to_raw_response_wrapper( + clusters.create, + ) + self.update = to_raw_response_wrapper( + clusters.update, + ) + self.list = to_raw_response_wrapper( + clusters.list, + ) + self.delete = to_raw_response_wrapper( + clusters.delete, + ) + self.action = to_raw_response_wrapper( + clusters.action, + ) + self.get = to_raw_response_wrapper( + clusters.get, + ) + + @cached_property + def servers(self) -> ServersResourceWithRawResponse: + return ServersResourceWithRawResponse(self._clusters.servers) + + @cached_property + def volumes(self) -> VolumesResourceWithRawResponse: + return VolumesResourceWithRawResponse(self._clusters.volumes) + + @cached_property + def interfaces(self) -> InterfacesResourceWithRawResponse: + return InterfacesResourceWithRawResponse(self._clusters.interfaces) + + @cached_property + def flavors(self) -> FlavorsResourceWithRawResponse: + return FlavorsResourceWithRawResponse(self._clusters.flavors) + + @cached_property + def images(self) -> ImagesResourceWithRawResponse: + return ImagesResourceWithRawResponse(self._clusters.images) + + +class AsyncClustersResourceWithRawResponse: + def __init__(self, clusters: AsyncClustersResource) -> None: + self._clusters = clusters + + self.create = async_to_raw_response_wrapper( + clusters.create, + ) + self.update = async_to_raw_response_wrapper( + clusters.update, + ) + self.list = async_to_raw_response_wrapper( + clusters.list, + ) + self.delete = async_to_raw_response_wrapper( + clusters.delete, + ) + self.action = async_to_raw_response_wrapper( + clusters.action, + ) + self.get = async_to_raw_response_wrapper( + clusters.get, + ) + + @cached_property + def servers(self) -> AsyncServersResourceWithRawResponse: + return AsyncServersResourceWithRawResponse(self._clusters.servers) + + @cached_property + def volumes(self) -> AsyncVolumesResourceWithRawResponse: + return AsyncVolumesResourceWithRawResponse(self._clusters.volumes) + + @cached_property + def interfaces(self) -> AsyncInterfacesResourceWithRawResponse: + return AsyncInterfacesResourceWithRawResponse(self._clusters.interfaces) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithRawResponse: + return AsyncFlavorsResourceWithRawResponse(self._clusters.flavors) + + @cached_property + def images(self) -> AsyncImagesResourceWithRawResponse: + return AsyncImagesResourceWithRawResponse(self._clusters.images) + + +class ClustersResourceWithStreamingResponse: + def __init__(self, clusters: ClustersResource) -> None: + self._clusters = clusters + + self.create = to_streamed_response_wrapper( + clusters.create, + ) + self.update = to_streamed_response_wrapper( + clusters.update, + ) + self.list = to_streamed_response_wrapper( + clusters.list, + ) + self.delete = to_streamed_response_wrapper( + clusters.delete, + ) + self.action = to_streamed_response_wrapper( + clusters.action, + ) + self.get = to_streamed_response_wrapper( + clusters.get, + ) + + @cached_property + def servers(self) -> ServersResourceWithStreamingResponse: + return ServersResourceWithStreamingResponse(self._clusters.servers) + + @cached_property + def volumes(self) -> VolumesResourceWithStreamingResponse: + return VolumesResourceWithStreamingResponse(self._clusters.volumes) + + @cached_property + def interfaces(self) -> InterfacesResourceWithStreamingResponse: + return InterfacesResourceWithStreamingResponse(self._clusters.interfaces) + + @cached_property + def flavors(self) -> FlavorsResourceWithStreamingResponse: + return FlavorsResourceWithStreamingResponse(self._clusters.flavors) + + @cached_property + def images(self) -> ImagesResourceWithStreamingResponse: + return ImagesResourceWithStreamingResponse(self._clusters.images) + + +class AsyncClustersResourceWithStreamingResponse: + def __init__(self, clusters: AsyncClustersResource) -> None: + self._clusters = clusters + + self.create = async_to_streamed_response_wrapper( + clusters.create, + ) + self.update = async_to_streamed_response_wrapper( + clusters.update, + ) + self.list = async_to_streamed_response_wrapper( + clusters.list, + ) + self.delete = async_to_streamed_response_wrapper( + clusters.delete, + ) + self.action = async_to_streamed_response_wrapper( + clusters.action, + ) + self.get = async_to_streamed_response_wrapper( + clusters.get, + ) + + @cached_property + def servers(self) -> AsyncServersResourceWithStreamingResponse: + return AsyncServersResourceWithStreamingResponse(self._clusters.servers) + + @cached_property + def volumes(self) -> AsyncVolumesResourceWithStreamingResponse: + return AsyncVolumesResourceWithStreamingResponse(self._clusters.volumes) + + @cached_property + def interfaces(self) -> AsyncInterfacesResourceWithStreamingResponse: + return AsyncInterfacesResourceWithStreamingResponse(self._clusters.interfaces) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithStreamingResponse: + return AsyncFlavorsResourceWithStreamingResponse(self._clusters.flavors) + + @cached_property + def images(self) -> AsyncImagesResourceWithStreamingResponse: + return AsyncImagesResourceWithStreamingResponse(self._clusters.images) diff --git a/src/gcore/resources/cloud/gpu_virtual/clusters/flavors.py b/src/gcore/resources/cloud/gpu_virtual/clusters/flavors.py new file mode 100644 index 00000000..ee6fd7dc --- /dev/null +++ b/src/gcore/resources/cloud/gpu_virtual/clusters/flavors.py @@ -0,0 +1,211 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.gpu_virtual.clusters import flavor_list_params +from .....types.cloud.gpu_virtual.clusters.gpu_virtual_flavor_list import GPUVirtualFlavorList + +__all__ = ["FlavorsResource", "AsyncFlavorsResource"] + + +class FlavorsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> FlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return FlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return FlavorsResourceWithStreamingResponse(self) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + hide_disabled: bool | Omit = omit, + include_prices: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUVirtualFlavorList: + """ + List virtual GPU flavors + + Args: + project_id: Project ID + + region_id: Region ID + + hide_disabled: Set to `true` to remove the disabled flavors from the response. + + include_prices: Set to `true` if the response should include flavor prices. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/flavors", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "hide_disabled": hide_disabled, + "include_prices": include_prices, + }, + flavor_list_params.FlavorListParams, + ), + ), + cast_to=GPUVirtualFlavorList, + ) + + +class AsyncFlavorsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncFlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncFlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncFlavorsResourceWithStreamingResponse(self) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + hide_disabled: bool | Omit = omit, + include_prices: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUVirtualFlavorList: + """ + List virtual GPU flavors + + Args: + project_id: Project ID + + region_id: Region ID + + hide_disabled: Set to `true` to remove the disabled flavors from the response. + + include_prices: Set to `true` if the response should include flavor prices. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/flavors", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "hide_disabled": hide_disabled, + "include_prices": include_prices, + }, + flavor_list_params.FlavorListParams, + ), + ), + cast_to=GPUVirtualFlavorList, + ) + + +class FlavorsResourceWithRawResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_raw_response_wrapper( + flavors.list, + ) + + +class AsyncFlavorsResourceWithRawResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_raw_response_wrapper( + flavors.list, + ) + + +class FlavorsResourceWithStreamingResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_streamed_response_wrapper( + flavors.list, + ) + + +class AsyncFlavorsResourceWithStreamingResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_streamed_response_wrapper( + flavors.list, + ) diff --git a/src/gcore/resources/cloud/gpu_virtual/clusters/images.py b/src/gcore/resources/cloud/gpu_virtual/clusters/images.py new file mode 100644 index 00000000..d83f68fa --- /dev/null +++ b/src/gcore/resources/cloud/gpu_virtual/clusters/images.py @@ -0,0 +1,582 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.gpu_image import GPUImage +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.gpu_image_list import GPUImageList +from .....types.cloud.gpu_virtual.clusters import image_upload_params + +__all__ = ["ImagesResource", "AsyncImagesResource"] + + +class ImagesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ImagesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ImagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ImagesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ImagesResourceWithStreamingResponse(self) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUImageList: + """ + List virtual GPU images + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUImageList, + ) + + def delete( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete virtual GPU image + + Args: + project_id: Project ID + + region_id: Region ID + + image_id: Image ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return self._delete( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images/{image_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUImage: + """ + Get virtual GPU image + + Args: + project_id: Project ID + + region_id: Region ID + + image_id: Image ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images/{image_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUImage, + ) + + def upload( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + url: str, + architecture: Optional[Literal["aarch64", "x86_64"]] | Omit = omit, + cow_format: bool | Omit = omit, + hw_firmware_type: Optional[Literal["bios", "uefi"]] | Omit = omit, + os_distro: Optional[str] | Omit = omit, + os_type: Optional[Literal["linux", "windows"]] | Omit = omit, + os_version: Optional[str] | Omit = omit, + ssh_key: Literal["allow", "deny", "required"] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Upload new virtual GPU image + + Args: + project_id: Project ID + + region_id: Region ID + + name: Image name + + url: Image URL + + architecture: Image architecture type: aarch64, `x86_64` + + cow_format: When True, image cannot be deleted unless all volumes, created from it, are + deleted. + + hw_firmware_type: Specifies the type of firmware with which to boot the guest. + + os_distro: OS Distribution, i.e. Debian, CentOS, Ubuntu, CoreOS etc. + + os_type: The operating system installed on the image. Linux by default + + os_version: OS version, i.e. 19.04 (for Ubuntu) or 9.4 for Debian + + ssh_key: Permission to use a ssh key in instances + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images", + body=maybe_transform( + { + "name": name, + "url": url, + "architecture": architecture, + "cow_format": cow_format, + "hw_firmware_type": hw_firmware_type, + "os_distro": os_distro, + "os_type": os_type, + "os_version": os_version, + "ssh_key": ssh_key, + "tags": tags, + }, + image_upload_params.ImageUploadParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncImagesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncImagesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncImagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncImagesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncImagesResourceWithStreamingResponse(self) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUImageList: + """ + List virtual GPU images + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUImageList, + ) + + async def delete( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete virtual GPU image + + Args: + project_id: Project ID + + region_id: Region ID + + image_id: Image ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return await self._delete( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images/{image_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUImage: + """ + Get virtual GPU image + + Args: + project_id: Project ID + + region_id: Region ID + + image_id: Image ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return await self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images/{image_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUImage, + ) + + async def upload( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + url: str, + architecture: Optional[Literal["aarch64", "x86_64"]] | Omit = omit, + cow_format: bool | Omit = omit, + hw_firmware_type: Optional[Literal["bios", "uefi"]] | Omit = omit, + os_distro: Optional[str] | Omit = omit, + os_type: Optional[Literal["linux", "windows"]] | Omit = omit, + os_version: Optional[str] | Omit = omit, + ssh_key: Literal["allow", "deny", "required"] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Upload new virtual GPU image + + Args: + project_id: Project ID + + region_id: Region ID + + name: Image name + + url: Image URL + + architecture: Image architecture type: aarch64, `x86_64` + + cow_format: When True, image cannot be deleted unless all volumes, created from it, are + deleted. + + hw_firmware_type: Specifies the type of firmware with which to boot the guest. + + os_distro: OS Distribution, i.e. Debian, CentOS, Ubuntu, CoreOS etc. + + os_type: The operating system installed on the image. Linux by default + + os_version: OS version, i.e. 19.04 (for Ubuntu) or 9.4 for Debian + + ssh_key: Permission to use a ssh key in instances + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/images", + body=await async_maybe_transform( + { + "name": name, + "url": url, + "architecture": architecture, + "cow_format": cow_format, + "hw_firmware_type": hw_firmware_type, + "os_distro": os_distro, + "os_type": os_type, + "os_version": os_version, + "ssh_key": ssh_key, + "tags": tags, + }, + image_upload_params.ImageUploadParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class ImagesResourceWithRawResponse: + def __init__(self, images: ImagesResource) -> None: + self._images = images + + self.list = to_raw_response_wrapper( + images.list, + ) + self.delete = to_raw_response_wrapper( + images.delete, + ) + self.get = to_raw_response_wrapper( + images.get, + ) + self.upload = to_raw_response_wrapper( + images.upload, + ) + + +class AsyncImagesResourceWithRawResponse: + def __init__(self, images: AsyncImagesResource) -> None: + self._images = images + + self.list = async_to_raw_response_wrapper( + images.list, + ) + self.delete = async_to_raw_response_wrapper( + images.delete, + ) + self.get = async_to_raw_response_wrapper( + images.get, + ) + self.upload = async_to_raw_response_wrapper( + images.upload, + ) + + +class ImagesResourceWithStreamingResponse: + def __init__(self, images: ImagesResource) -> None: + self._images = images + + self.list = to_streamed_response_wrapper( + images.list, + ) + self.delete = to_streamed_response_wrapper( + images.delete, + ) + self.get = to_streamed_response_wrapper( + images.get, + ) + self.upload = to_streamed_response_wrapper( + images.upload, + ) + + +class AsyncImagesResourceWithStreamingResponse: + def __init__(self, images: AsyncImagesResource) -> None: + self._images = images + + self.list = async_to_streamed_response_wrapper( + images.list, + ) + self.delete = async_to_streamed_response_wrapper( + images.delete, + ) + self.get = async_to_streamed_response_wrapper( + images.get, + ) + self.upload = async_to_streamed_response_wrapper( + images.upload, + ) diff --git a/src/gcore/resources/cloud/gpu_virtual/clusters/interfaces.py b/src/gcore/resources/cloud/gpu_virtual/clusters/interfaces.py new file mode 100644 index 00000000..28bae5d4 --- /dev/null +++ b/src/gcore/resources/cloud/gpu_virtual/clusters/interfaces.py @@ -0,0 +1,187 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import Body, Query, Headers, NotGiven, not_given +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.gpu_virtual.clusters.gpu_virtual_interface_list import GPUVirtualInterfaceList + +__all__ = ["InterfacesResource", "AsyncInterfacesResource"] + + +class InterfacesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> InterfacesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return InterfacesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InterfacesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return InterfacesResourceWithStreamingResponse(self) + + def list( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUVirtualInterfaceList: + """ + List all network interfaces for servers in a virtual GPU cluster. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/interfaces", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUVirtualInterfaceList, + ) + + +class AsyncInterfacesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncInterfacesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncInterfacesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInterfacesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncInterfacesResourceWithStreamingResponse(self) + + async def list( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUVirtualInterfaceList: + """ + List all network interfaces for servers in a virtual GPU cluster. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/interfaces", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUVirtualInterfaceList, + ) + + +class InterfacesResourceWithRawResponse: + def __init__(self, interfaces: InterfacesResource) -> None: + self._interfaces = interfaces + + self.list = to_raw_response_wrapper( + interfaces.list, + ) + + +class AsyncInterfacesResourceWithRawResponse: + def __init__(self, interfaces: AsyncInterfacesResource) -> None: + self._interfaces = interfaces + + self.list = async_to_raw_response_wrapper( + interfaces.list, + ) + + +class InterfacesResourceWithStreamingResponse: + def __init__(self, interfaces: InterfacesResource) -> None: + self._interfaces = interfaces + + self.list = to_streamed_response_wrapper( + interfaces.list, + ) + + +class AsyncInterfacesResourceWithStreamingResponse: + def __init__(self, interfaces: AsyncInterfacesResource) -> None: + self._interfaces = interfaces + + self.list = async_to_streamed_response_wrapper( + interfaces.list, + ) diff --git a/src/gcore/resources/cloud/gpu_virtual/clusters/servers.py b/src/gcore/resources/cloud/gpu_virtual/clusters/servers.py new file mode 100644 index 00000000..4895fd83 --- /dev/null +++ b/src/gcore/resources/cloud/gpu_virtual/clusters/servers.py @@ -0,0 +1,506 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.gpu_virtual.clusters import server_list_params, server_delete_params +from .....types.cloud.gpu_virtual.clusters.gpu_virtual_cluster_server_list import GPUVirtualClusterServerList + +__all__ = ["ServersResource", "AsyncServersResource"] + + +class ServersResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ServersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ServersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ServersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ServersResourceWithStreamingResponse(self) + + def list( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + changed_before: Union[str, datetime] | Omit = omit, + changed_since: Union[str, datetime] | Omit = omit, + ip_address: str | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["created_at.asc", "created_at.desc", "status.asc", "status.desc"] | Omit = omit, + status: Literal[ + "ACTIVE", + "BUILD", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PAUSED", + "REBOOT", + "REBUILD", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "VERIFY_RESIZE", + ] + | Omit = omit, + uuids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUVirtualClusterServerList: + """ + List all servers in a virtual GPU cluster. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + changed_before: Filters the results to include only servers whose last change timestamp is less + than the specified datetime. Format: ISO 8601. + + changed_since: Filters the results to include only servers whose last change timestamp is + greater than or equal to the specified datetime. Format: ISO 8601. + + ip_address: Filter servers by ip address. + + limit: Limit of items on a single page + + name: Filter servers by name. You can provide a full or partial name, servers with + matching names will be returned. For example, entering 'test' will return all + servers that contain 'test' in their name. + + offset: Offset in results list + + order_by: Order field + + status: Filters servers by status. + + uuids: Filter servers by uuid. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/servers", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "changed_before": changed_before, + "changed_since": changed_since, + "ip_address": ip_address, + "limit": limit, + "name": name, + "offset": offset, + "order_by": order_by, + "status": status, + "uuids": uuids, + }, + server_list_params.ServerListParams, + ), + ), + cast_to=GPUVirtualClusterServerList, + ) + + def delete( + self, + server_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_id: str, + all_floating_ips: bool | Omit = omit, + all_reserved_fixed_ips: bool | Omit = omit, + all_volumes: bool | Omit = omit, + floating_ip_ids: SequenceNotStr[str] | Omit = omit, + reserved_fixed_ip_ids: SequenceNotStr[str] | Omit = omit, + volume_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a server from a virtual GPU cluster and its associated resources. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + server_id: Server unique identifier + + all_floating_ips: Flag indicating whether the floating ips associated with server / cluster are + deleted + + all_reserved_fixed_ips: Flag indicating whether the reserved fixed ips associated with server / cluster + are deleted + + all_volumes: Flag indicating whether all attached volumes are deleted + + floating_ip_ids: Optional list of floating ips to be deleted + + reserved_fixed_ip_ids: Optional list of reserved fixed ips to be deleted + + volume_ids: Optional list of volumes to be deleted + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + if not server_id: + raise ValueError(f"Expected a non-empty value for `server_id` but received {server_id!r}") + return self._delete( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/servers/{server_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "all_floating_ips": all_floating_ips, + "all_reserved_fixed_ips": all_reserved_fixed_ips, + "all_volumes": all_volumes, + "floating_ip_ids": floating_ip_ids, + "reserved_fixed_ip_ids": reserved_fixed_ip_ids, + "volume_ids": volume_ids, + }, + server_delete_params.ServerDeleteParams, + ), + ), + cast_to=TaskIDList, + ) + + +class AsyncServersResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncServersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncServersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncServersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncServersResourceWithStreamingResponse(self) + + async def list( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + changed_before: Union[str, datetime] | Omit = omit, + changed_since: Union[str, datetime] | Omit = omit, + ip_address: str | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["created_at.asc", "created_at.desc", "status.asc", "status.desc"] | Omit = omit, + status: Literal[ + "ACTIVE", + "BUILD", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PAUSED", + "REBOOT", + "REBUILD", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "VERIFY_RESIZE", + ] + | Omit = omit, + uuids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUVirtualClusterServerList: + """ + List all servers in a virtual GPU cluster. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + changed_before: Filters the results to include only servers whose last change timestamp is less + than the specified datetime. Format: ISO 8601. + + changed_since: Filters the results to include only servers whose last change timestamp is + greater than or equal to the specified datetime. Format: ISO 8601. + + ip_address: Filter servers by ip address. + + limit: Limit of items on a single page + + name: Filter servers by name. You can provide a full or partial name, servers with + matching names will be returned. For example, entering 'test' will return all + servers that contain 'test' in their name. + + offset: Offset in results list + + order_by: Order field + + status: Filters servers by status. + + uuids: Filter servers by uuid. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/servers", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "changed_before": changed_before, + "changed_since": changed_since, + "ip_address": ip_address, + "limit": limit, + "name": name, + "offset": offset, + "order_by": order_by, + "status": status, + "uuids": uuids, + }, + server_list_params.ServerListParams, + ), + ), + cast_to=GPUVirtualClusterServerList, + ) + + async def delete( + self, + server_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_id: str, + all_floating_ips: bool | Omit = omit, + all_reserved_fixed_ips: bool | Omit = omit, + all_volumes: bool | Omit = omit, + floating_ip_ids: SequenceNotStr[str] | Omit = omit, + reserved_fixed_ip_ids: SequenceNotStr[str] | Omit = omit, + volume_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a server from a virtual GPU cluster and its associated resources. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + server_id: Server unique identifier + + all_floating_ips: Flag indicating whether the floating ips associated with server / cluster are + deleted + + all_reserved_fixed_ips: Flag indicating whether the reserved fixed ips associated with server / cluster + are deleted + + all_volumes: Flag indicating whether all attached volumes are deleted + + floating_ip_ids: Optional list of floating ips to be deleted + + reserved_fixed_ip_ids: Optional list of reserved fixed ips to be deleted + + volume_ids: Optional list of volumes to be deleted + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + if not server_id: + raise ValueError(f"Expected a non-empty value for `server_id` but received {server_id!r}") + return await self._delete( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/servers/{server_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "all_floating_ips": all_floating_ips, + "all_reserved_fixed_ips": all_reserved_fixed_ips, + "all_volumes": all_volumes, + "floating_ip_ids": floating_ip_ids, + "reserved_fixed_ip_ids": reserved_fixed_ip_ids, + "volume_ids": volume_ids, + }, + server_delete_params.ServerDeleteParams, + ), + ), + cast_to=TaskIDList, + ) + + +class ServersResourceWithRawResponse: + def __init__(self, servers: ServersResource) -> None: + self._servers = servers + + self.list = to_raw_response_wrapper( + servers.list, + ) + self.delete = to_raw_response_wrapper( + servers.delete, + ) + + +class AsyncServersResourceWithRawResponse: + def __init__(self, servers: AsyncServersResource) -> None: + self._servers = servers + + self.list = async_to_raw_response_wrapper( + servers.list, + ) + self.delete = async_to_raw_response_wrapper( + servers.delete, + ) + + +class ServersResourceWithStreamingResponse: + def __init__(self, servers: ServersResource) -> None: + self._servers = servers + + self.list = to_streamed_response_wrapper( + servers.list, + ) + self.delete = to_streamed_response_wrapper( + servers.delete, + ) + + +class AsyncServersResourceWithStreamingResponse: + def __init__(self, servers: AsyncServersResource) -> None: + self._servers = servers + + self.list = async_to_streamed_response_wrapper( + servers.list, + ) + self.delete = async_to_streamed_response_wrapper( + servers.delete, + ) diff --git a/src/gcore/resources/cloud/gpu_virtual/clusters/volumes.py b/src/gcore/resources/cloud/gpu_virtual/clusters/volumes.py new file mode 100644 index 00000000..afa07662 --- /dev/null +++ b/src/gcore/resources/cloud/gpu_virtual/clusters/volumes.py @@ -0,0 +1,187 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import Body, Query, Headers, NotGiven, not_given +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.gpu_virtual.clusters.gpu_virtual_cluster_volume_list import GPUVirtualClusterVolumeList + +__all__ = ["VolumesResource", "AsyncVolumesResource"] + + +class VolumesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> VolumesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return VolumesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> VolumesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return VolumesResourceWithStreamingResponse(self) + + def list( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUVirtualClusterVolumeList: + """ + List all volumes attached to servers in a virtual GPU cluster. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/volumes", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUVirtualClusterVolumeList, + ) + + +class AsyncVolumesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncVolumesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncVolumesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncVolumesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncVolumesResourceWithStreamingResponse(self) + + async def list( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> GPUVirtualClusterVolumeList: + """ + List all volumes attached to servers in a virtual GPU cluster. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_id: Cluster unique identifier + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_id: + raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}") + return await self._get( + f"/cloud/v3/gpu/virtual/{project_id}/{region_id}/clusters/{cluster_id}/volumes", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GPUVirtualClusterVolumeList, + ) + + +class VolumesResourceWithRawResponse: + def __init__(self, volumes: VolumesResource) -> None: + self._volumes = volumes + + self.list = to_raw_response_wrapper( + volumes.list, + ) + + +class AsyncVolumesResourceWithRawResponse: + def __init__(self, volumes: AsyncVolumesResource) -> None: + self._volumes = volumes + + self.list = async_to_raw_response_wrapper( + volumes.list, + ) + + +class VolumesResourceWithStreamingResponse: + def __init__(self, volumes: VolumesResource) -> None: + self._volumes = volumes + + self.list = to_streamed_response_wrapper( + volumes.list, + ) + + +class AsyncVolumesResourceWithStreamingResponse: + def __init__(self, volumes: AsyncVolumesResource) -> None: + self._volumes = volumes + + self.list = async_to_streamed_response_wrapper( + volumes.list, + ) diff --git a/src/gcore/resources/cloud/gpu_virtual/gpu_virtual.py b/src/gcore/resources/cloud/gpu_virtual/gpu_virtual.py new file mode 100644 index 00000000..959b2156 --- /dev/null +++ b/src/gcore/resources/cloud/gpu_virtual/gpu_virtual.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from .clusters.clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) + +__all__ = ["GPUVirtualResource", "AsyncGPUVirtualResource"] + + +class GPUVirtualResource(SyncAPIResource): + @cached_property + def clusters(self) -> ClustersResource: + return ClustersResource(self._client) + + @cached_property + def with_raw_response(self) -> GPUVirtualResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return GPUVirtualResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> GPUVirtualResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return GPUVirtualResourceWithStreamingResponse(self) + + +class AsyncGPUVirtualResource(AsyncAPIResource): + @cached_property + def clusters(self) -> AsyncClustersResource: + return AsyncClustersResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncGPUVirtualResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncGPUVirtualResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncGPUVirtualResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncGPUVirtualResourceWithStreamingResponse(self) + + +class GPUVirtualResourceWithRawResponse: + def __init__(self, gpu_virtual: GPUVirtualResource) -> None: + self._gpu_virtual = gpu_virtual + + @cached_property + def clusters(self) -> ClustersResourceWithRawResponse: + return ClustersResourceWithRawResponse(self._gpu_virtual.clusters) + + +class AsyncGPUVirtualResourceWithRawResponse: + def __init__(self, gpu_virtual: AsyncGPUVirtualResource) -> None: + self._gpu_virtual = gpu_virtual + + @cached_property + def clusters(self) -> AsyncClustersResourceWithRawResponse: + return AsyncClustersResourceWithRawResponse(self._gpu_virtual.clusters) + + +class GPUVirtualResourceWithStreamingResponse: + def __init__(self, gpu_virtual: GPUVirtualResource) -> None: + self._gpu_virtual = gpu_virtual + + @cached_property + def clusters(self) -> ClustersResourceWithStreamingResponse: + return ClustersResourceWithStreamingResponse(self._gpu_virtual.clusters) + + +class AsyncGPUVirtualResourceWithStreamingResponse: + def __init__(self, gpu_virtual: AsyncGPUVirtualResource) -> None: + self._gpu_virtual = gpu_virtual + + @cached_property + def clusters(self) -> AsyncClustersResourceWithStreamingResponse: + return AsyncClustersResourceWithStreamingResponse(self._gpu_virtual.clusters) diff --git a/src/gcore/resources/cloud/inference/__init__.py b/src/gcore/resources/cloud/inference/__init__.py new file mode 100644 index 00000000..a3cd64c3 --- /dev/null +++ b/src/gcore/resources/cloud/inference/__init__.py @@ -0,0 +1,103 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from .secrets import ( + SecretsResource, + AsyncSecretsResource, + SecretsResourceWithRawResponse, + AsyncSecretsResourceWithRawResponse, + SecretsResourceWithStreamingResponse, + AsyncSecretsResourceWithStreamingResponse, +) +from .api_keys import ( + APIKeysResource, + AsyncAPIKeysResource, + APIKeysResourceWithRawResponse, + AsyncAPIKeysResourceWithRawResponse, + APIKeysResourceWithStreamingResponse, + AsyncAPIKeysResourceWithStreamingResponse, +) +from .inference import ( + InferenceResource, + AsyncInferenceResource, + InferenceResourceWithRawResponse, + AsyncInferenceResourceWithRawResponse, + InferenceResourceWithStreamingResponse, + AsyncInferenceResourceWithStreamingResponse, +) +from .deployments import ( + DeploymentsResource, + AsyncDeploymentsResource, + DeploymentsResourceWithRawResponse, + AsyncDeploymentsResourceWithRawResponse, + DeploymentsResourceWithStreamingResponse, + AsyncDeploymentsResourceWithStreamingResponse, +) +from .applications import ( + ApplicationsResource, + AsyncApplicationsResource, + ApplicationsResourceWithRawResponse, + AsyncApplicationsResourceWithRawResponse, + ApplicationsResourceWithStreamingResponse, + AsyncApplicationsResourceWithStreamingResponse, +) +from .registry_credentials import ( + RegistryCredentialsResource, + AsyncRegistryCredentialsResource, + RegistryCredentialsResourceWithRawResponse, + AsyncRegistryCredentialsResourceWithRawResponse, + RegistryCredentialsResourceWithStreamingResponse, + AsyncRegistryCredentialsResourceWithStreamingResponse, +) + +__all__ = [ + "FlavorsResource", + "AsyncFlavorsResource", + "FlavorsResourceWithRawResponse", + "AsyncFlavorsResourceWithRawResponse", + "FlavorsResourceWithStreamingResponse", + "AsyncFlavorsResourceWithStreamingResponse", + "DeploymentsResource", + "AsyncDeploymentsResource", + "DeploymentsResourceWithRawResponse", + "AsyncDeploymentsResourceWithRawResponse", + "DeploymentsResourceWithStreamingResponse", + "AsyncDeploymentsResourceWithStreamingResponse", + "RegistryCredentialsResource", + "AsyncRegistryCredentialsResource", + "RegistryCredentialsResourceWithRawResponse", + "AsyncRegistryCredentialsResourceWithRawResponse", + "RegistryCredentialsResourceWithStreamingResponse", + "AsyncRegistryCredentialsResourceWithStreamingResponse", + "SecretsResource", + "AsyncSecretsResource", + "SecretsResourceWithRawResponse", + "AsyncSecretsResourceWithRawResponse", + "SecretsResourceWithStreamingResponse", + "AsyncSecretsResourceWithStreamingResponse", + "APIKeysResource", + "AsyncAPIKeysResource", + "APIKeysResourceWithRawResponse", + "AsyncAPIKeysResourceWithRawResponse", + "APIKeysResourceWithStreamingResponse", + "AsyncAPIKeysResourceWithStreamingResponse", + "ApplicationsResource", + "AsyncApplicationsResource", + "ApplicationsResourceWithRawResponse", + "AsyncApplicationsResourceWithRawResponse", + "ApplicationsResourceWithStreamingResponse", + "AsyncApplicationsResourceWithStreamingResponse", + "InferenceResource", + "AsyncInferenceResource", + "InferenceResourceWithRawResponse", + "AsyncInferenceResourceWithRawResponse", + "InferenceResourceWithStreamingResponse", + "AsyncInferenceResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/inference/api_keys.py b/src/gcore/resources/cloud/inference/api_keys.py new file mode 100644 index 00000000..37e51cd0 --- /dev/null +++ b/src/gcore/resources/cloud/inference/api_keys.py @@ -0,0 +1,621 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.inference import api_key_list_params, api_key_create_params, api_key_update_params +from ....types.cloud.inference.inference_api_key import InferenceAPIKey +from ....types.cloud.inference.inference_api_key_created import InferenceAPIKeyCreated + +__all__ = ["APIKeysResource", "AsyncAPIKeysResource"] + + +class APIKeysResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> APIKeysResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return APIKeysResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> APIKeysResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return APIKeysResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + name: str, + description: str | Omit = omit, + expires_at: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceAPIKeyCreated: + """This endpoint creates a new API key for everywhere inference. + + It returs api + key's actual secret only once after creation. + + Args: + project_id: Project ID + + name: Name of the API Key. + + description: Description of the API Key. + + expires_at: Expiration date of the API Key in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._post( + f"/cloud/v3/inference/{project_id}/api_keys", + body=maybe_transform( + { + "name": name, + "description": description, + "expires_at": expires_at, + }, + api_key_create_params.APIKeyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceAPIKeyCreated, + ) + + def update( + self, + api_key_name: str, + *, + project_id: int | None = None, + description: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceAPIKey: + """ + This endpoint updates a specific API key for everywhere inference. + + Args: + project_id: Project ID + + api_key_name: Api key name. + + description: Description of the API Key. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not api_key_name: + raise ValueError(f"Expected a non-empty value for `api_key_name` but received {api_key_name!r}") + return self._patch( + f"/cloud/v3/inference/{project_id}/api_keys/{api_key_name}", + body=maybe_transform({"description": description}, api_key_update_params.APIKeyUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceAPIKey, + ) + + def list( + self, + *, + project_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[InferenceAPIKey]: + """ + This endpoint retrieves a list of API keys for everywhere inference. + + Args: + project_id: Project ID + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._get_api_list( + f"/cloud/v3/inference/{project_id}/api_keys", + page=SyncOffsetPage[InferenceAPIKey], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + api_key_list_params.APIKeyListParams, + ), + ), + model=InferenceAPIKey, + ) + + def delete( + self, + api_key_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """This endpoint deletes a specific API key for everywhere inference. + + If the API + key is attached to any inference deployments, it will not be removed. + ConflictError will be raised + + Args: + project_id: Project ID + + api_key_name: Api key name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not api_key_name: + raise ValueError(f"Expected a non-empty value for `api_key_name` but received {api_key_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v3/inference/{project_id}/api_keys/{api_key_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + api_key_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceAPIKey: + """ + This endpoint retrieves a specific API key for everywhere inference. + + Args: + project_id: Project ID + + api_key_name: Api key name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not api_key_name: + raise ValueError(f"Expected a non-empty value for `api_key_name` but received {api_key_name!r}") + return self._get( + f"/cloud/v3/inference/{project_id}/api_keys/{api_key_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceAPIKey, + ) + + +class AsyncAPIKeysResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAPIKeysResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncAPIKeysResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAPIKeysResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncAPIKeysResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + name: str, + description: str | Omit = omit, + expires_at: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceAPIKeyCreated: + """This endpoint creates a new API key for everywhere inference. + + It returs api + key's actual secret only once after creation. + + Args: + project_id: Project ID + + name: Name of the API Key. + + description: Description of the API Key. + + expires_at: Expiration date of the API Key in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return await self._post( + f"/cloud/v3/inference/{project_id}/api_keys", + body=await async_maybe_transform( + { + "name": name, + "description": description, + "expires_at": expires_at, + }, + api_key_create_params.APIKeyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceAPIKeyCreated, + ) + + async def update( + self, + api_key_name: str, + *, + project_id: int | None = None, + description: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceAPIKey: + """ + This endpoint updates a specific API key for everywhere inference. + + Args: + project_id: Project ID + + api_key_name: Api key name. + + description: Description of the API Key. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not api_key_name: + raise ValueError(f"Expected a non-empty value for `api_key_name` but received {api_key_name!r}") + return await self._patch( + f"/cloud/v3/inference/{project_id}/api_keys/{api_key_name}", + body=await async_maybe_transform({"description": description}, api_key_update_params.APIKeyUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceAPIKey, + ) + + def list( + self, + *, + project_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[InferenceAPIKey, AsyncOffsetPage[InferenceAPIKey]]: + """ + This endpoint retrieves a list of API keys for everywhere inference. + + Args: + project_id: Project ID + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._get_api_list( + f"/cloud/v3/inference/{project_id}/api_keys", + page=AsyncOffsetPage[InferenceAPIKey], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + api_key_list_params.APIKeyListParams, + ), + ), + model=InferenceAPIKey, + ) + + async def delete( + self, + api_key_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """This endpoint deletes a specific API key for everywhere inference. + + If the API + key is attached to any inference deployments, it will not be removed. + ConflictError will be raised + + Args: + project_id: Project ID + + api_key_name: Api key name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not api_key_name: + raise ValueError(f"Expected a non-empty value for `api_key_name` but received {api_key_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v3/inference/{project_id}/api_keys/{api_key_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + api_key_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceAPIKey: + """ + This endpoint retrieves a specific API key for everywhere inference. + + Args: + project_id: Project ID + + api_key_name: Api key name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not api_key_name: + raise ValueError(f"Expected a non-empty value for `api_key_name` but received {api_key_name!r}") + return await self._get( + f"/cloud/v3/inference/{project_id}/api_keys/{api_key_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceAPIKey, + ) + + +class APIKeysResourceWithRawResponse: + def __init__(self, api_keys: APIKeysResource) -> None: + self._api_keys = api_keys + + self.create = to_raw_response_wrapper( + api_keys.create, + ) + self.update = to_raw_response_wrapper( + api_keys.update, + ) + self.list = to_raw_response_wrapper( + api_keys.list, + ) + self.delete = to_raw_response_wrapper( + api_keys.delete, + ) + self.get = to_raw_response_wrapper( + api_keys.get, + ) + + +class AsyncAPIKeysResourceWithRawResponse: + def __init__(self, api_keys: AsyncAPIKeysResource) -> None: + self._api_keys = api_keys + + self.create = async_to_raw_response_wrapper( + api_keys.create, + ) + self.update = async_to_raw_response_wrapper( + api_keys.update, + ) + self.list = async_to_raw_response_wrapper( + api_keys.list, + ) + self.delete = async_to_raw_response_wrapper( + api_keys.delete, + ) + self.get = async_to_raw_response_wrapper( + api_keys.get, + ) + + +class APIKeysResourceWithStreamingResponse: + def __init__(self, api_keys: APIKeysResource) -> None: + self._api_keys = api_keys + + self.create = to_streamed_response_wrapper( + api_keys.create, + ) + self.update = to_streamed_response_wrapper( + api_keys.update, + ) + self.list = to_streamed_response_wrapper( + api_keys.list, + ) + self.delete = to_streamed_response_wrapper( + api_keys.delete, + ) + self.get = to_streamed_response_wrapper( + api_keys.get, + ) + + +class AsyncAPIKeysResourceWithStreamingResponse: + def __init__(self, api_keys: AsyncAPIKeysResource) -> None: + self._api_keys = api_keys + + self.create = async_to_streamed_response_wrapper( + api_keys.create, + ) + self.update = async_to_streamed_response_wrapper( + api_keys.update, + ) + self.list = async_to_streamed_response_wrapper( + api_keys.list, + ) + self.delete = async_to_streamed_response_wrapper( + api_keys.delete, + ) + self.get = async_to_streamed_response_wrapper( + api_keys.get, + ) diff --git a/src/gcore/resources/cloud/inference/applications/__init__.py b/src/gcore/resources/cloud/inference/applications/__init__.py new file mode 100644 index 00000000..a84524c1 --- /dev/null +++ b/src/gcore/resources/cloud/inference/applications/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .templates import ( + TemplatesResource, + AsyncTemplatesResource, + TemplatesResourceWithRawResponse, + AsyncTemplatesResourceWithRawResponse, + TemplatesResourceWithStreamingResponse, + AsyncTemplatesResourceWithStreamingResponse, +) +from .deployments import ( + DeploymentsResource, + AsyncDeploymentsResource, + DeploymentsResourceWithRawResponse, + AsyncDeploymentsResourceWithRawResponse, + DeploymentsResourceWithStreamingResponse, + AsyncDeploymentsResourceWithStreamingResponse, +) +from .applications import ( + ApplicationsResource, + AsyncApplicationsResource, + ApplicationsResourceWithRawResponse, + AsyncApplicationsResourceWithRawResponse, + ApplicationsResourceWithStreamingResponse, + AsyncApplicationsResourceWithStreamingResponse, +) + +__all__ = [ + "DeploymentsResource", + "AsyncDeploymentsResource", + "DeploymentsResourceWithRawResponse", + "AsyncDeploymentsResourceWithRawResponse", + "DeploymentsResourceWithStreamingResponse", + "AsyncDeploymentsResourceWithStreamingResponse", + "TemplatesResource", + "AsyncTemplatesResource", + "TemplatesResourceWithRawResponse", + "AsyncTemplatesResourceWithRawResponse", + "TemplatesResourceWithStreamingResponse", + "AsyncTemplatesResourceWithStreamingResponse", + "ApplicationsResource", + "AsyncApplicationsResource", + "ApplicationsResourceWithRawResponse", + "AsyncApplicationsResourceWithRawResponse", + "ApplicationsResourceWithStreamingResponse", + "AsyncApplicationsResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/inference/applications/applications.py b/src/gcore/resources/cloud/inference/applications/applications.py new file mode 100644 index 00000000..05a3a528 --- /dev/null +++ b/src/gcore/resources/cloud/inference/applications/applications.py @@ -0,0 +1,134 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .templates import ( + TemplatesResource, + AsyncTemplatesResource, + TemplatesResourceWithRawResponse, + AsyncTemplatesResourceWithRawResponse, + TemplatesResourceWithStreamingResponse, + AsyncTemplatesResourceWithStreamingResponse, +) +from ....._compat import cached_property +from .deployments import ( + DeploymentsResource, + AsyncDeploymentsResource, + DeploymentsResourceWithRawResponse, + AsyncDeploymentsResourceWithRawResponse, + DeploymentsResourceWithStreamingResponse, + AsyncDeploymentsResourceWithStreamingResponse, +) +from ....._resource import SyncAPIResource, AsyncAPIResource + +__all__ = ["ApplicationsResource", "AsyncApplicationsResource"] + + +class ApplicationsResource(SyncAPIResource): + @cached_property + def deployments(self) -> DeploymentsResource: + return DeploymentsResource(self._client) + + @cached_property + def templates(self) -> TemplatesResource: + return TemplatesResource(self._client) + + @cached_property + def with_raw_response(self) -> ApplicationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ApplicationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ApplicationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ApplicationsResourceWithStreamingResponse(self) + + +class AsyncApplicationsResource(AsyncAPIResource): + @cached_property + def deployments(self) -> AsyncDeploymentsResource: + return AsyncDeploymentsResource(self._client) + + @cached_property + def templates(self) -> AsyncTemplatesResource: + return AsyncTemplatesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncApplicationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncApplicationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncApplicationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncApplicationsResourceWithStreamingResponse(self) + + +class ApplicationsResourceWithRawResponse: + def __init__(self, applications: ApplicationsResource) -> None: + self._applications = applications + + @cached_property + def deployments(self) -> DeploymentsResourceWithRawResponse: + return DeploymentsResourceWithRawResponse(self._applications.deployments) + + @cached_property + def templates(self) -> TemplatesResourceWithRawResponse: + return TemplatesResourceWithRawResponse(self._applications.templates) + + +class AsyncApplicationsResourceWithRawResponse: + def __init__(self, applications: AsyncApplicationsResource) -> None: + self._applications = applications + + @cached_property + def deployments(self) -> AsyncDeploymentsResourceWithRawResponse: + return AsyncDeploymentsResourceWithRawResponse(self._applications.deployments) + + @cached_property + def templates(self) -> AsyncTemplatesResourceWithRawResponse: + return AsyncTemplatesResourceWithRawResponse(self._applications.templates) + + +class ApplicationsResourceWithStreamingResponse: + def __init__(self, applications: ApplicationsResource) -> None: + self._applications = applications + + @cached_property + def deployments(self) -> DeploymentsResourceWithStreamingResponse: + return DeploymentsResourceWithStreamingResponse(self._applications.deployments) + + @cached_property + def templates(self) -> TemplatesResourceWithStreamingResponse: + return TemplatesResourceWithStreamingResponse(self._applications.templates) + + +class AsyncApplicationsResourceWithStreamingResponse: + def __init__(self, applications: AsyncApplicationsResource) -> None: + self._applications = applications + + @cached_property + def deployments(self) -> AsyncDeploymentsResourceWithStreamingResponse: + return AsyncDeploymentsResourceWithStreamingResponse(self._applications.deployments) + + @cached_property + def templates(self) -> AsyncTemplatesResourceWithStreamingResponse: + return AsyncTemplatesResourceWithStreamingResponse(self._applications.templates) diff --git a/src/gcore/resources/cloud/inference/applications/deployments.py b/src/gcore/resources/cloud/inference/applications/deployments.py new file mode 100644 index 00000000..5bfac7b7 --- /dev/null +++ b/src/gcore/resources/cloud/inference/applications/deployments.py @@ -0,0 +1,647 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable, Optional + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.inference.applications import deployment_create_params, deployment_update_params +from .....types.cloud.inference.applications.inference_application_deployment import InferenceApplicationDeployment +from .....types.cloud.inference.applications.inference_application_deployment_list import ( + InferenceApplicationDeploymentList, +) + +__all__ = ["DeploymentsResource", "AsyncDeploymentsResource"] + + +class DeploymentsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DeploymentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return DeploymentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DeploymentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return DeploymentsResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + application_name: str, + components_configuration: Dict[str, deployment_create_params.ComponentsConfiguration], + name: str, + regions: Iterable[int], + api_keys: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Creates a new application deployment based on a selected catalog application. + Specify the desired deployment name, target regions, and configuration for each + component. The platform will provision the necessary resources and initialize + the application accordingly. + + Args: + project_id: Project ID + + application_name: Identifier of the application from the catalog + + components_configuration: Mapping of component names to their configuration (e.g., `"model": {...}`) + + name: Desired name for the new deployment + + regions: Geographical regions where the deployment should be created + + api_keys: List of API keys for the application + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._post( + f"/cloud/v3/inference/applications/{project_id}/deployments", + body=maybe_transform( + { + "application_name": application_name, + "components_configuration": components_configuration, + "name": name, + "regions": regions, + "api_keys": api_keys, + }, + deployment_create_params.DeploymentCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + deployment_name: str, + *, + project_id: int | None = None, + api_keys: SequenceNotStr[str] | Omit = omit, + components_configuration: Dict[str, Optional[deployment_update_params.ComponentsConfiguration]] | Omit = omit, + regions: Iterable[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Updates an existing application deployment. + + You can modify the target regions + and update configurations for individual components. To disable a component, set + its value to null. Only the provided fields will be updated; all others remain + unchanged. + + Args: + project_id: Project ID + + deployment_name: Name of deployment + + api_keys: List of API keys for the application + + components_configuration: Mapping of component names to their configuration (e.g., `"model": {...}`) + + regions: Geographical regions to be updated for the deployment + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return self._patch( + f"/cloud/v3/inference/applications/{project_id}/deployments/{deployment_name}", + body=maybe_transform( + { + "api_keys": api_keys, + "components_configuration": components_configuration, + "regions": regions, + }, + deployment_update_params.DeploymentUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceApplicationDeploymentList: + """ + Returns a list of your application deployments, including deployment names, + associated catalog applications, regions, component configurations, and current + status. Useful for monitoring and managing all active AI application instances. + + Args: + project_id: Project ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._get( + f"/cloud/v3/inference/applications/{project_id}/deployments", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceApplicationDeploymentList, + ) + + def delete( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Deletes an existing application deployment along with all associated resources. + This action will permanently remove the deployment and **terminate all related + inference instances** that are part of the application. + + Args: + project_id: Project ID + + deployment_name: Name of deployment + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return self._delete( + f"/cloud/v3/inference/applications/{project_id}/deployments/{deployment_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceApplicationDeployment: + """Retrieves detailed information about a specific application deployment. + + The + response includes the catalog application it was created from, deployment name, + active regions, configuration of each component, and the current status of the + deployment. + + Args: + project_id: Project ID + + deployment_name: Name of deployment + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return self._get( + f"/cloud/v3/inference/applications/{project_id}/deployments/{deployment_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceApplicationDeployment, + ) + + +class AsyncDeploymentsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDeploymentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncDeploymentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDeploymentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncDeploymentsResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + application_name: str, + components_configuration: Dict[str, deployment_create_params.ComponentsConfiguration], + name: str, + regions: Iterable[int], + api_keys: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Creates a new application deployment based on a selected catalog application. + Specify the desired deployment name, target regions, and configuration for each + component. The platform will provision the necessary resources and initialize + the application accordingly. + + Args: + project_id: Project ID + + application_name: Identifier of the application from the catalog + + components_configuration: Mapping of component names to their configuration (e.g., `"model": {...}`) + + name: Desired name for the new deployment + + regions: Geographical regions where the deployment should be created + + api_keys: List of API keys for the application + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return await self._post( + f"/cloud/v3/inference/applications/{project_id}/deployments", + body=await async_maybe_transform( + { + "application_name": application_name, + "components_configuration": components_configuration, + "name": name, + "regions": regions, + "api_keys": api_keys, + }, + deployment_create_params.DeploymentCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + deployment_name: str, + *, + project_id: int | None = None, + api_keys: SequenceNotStr[str] | Omit = omit, + components_configuration: Dict[str, Optional[deployment_update_params.ComponentsConfiguration]] | Omit = omit, + regions: Iterable[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Updates an existing application deployment. + + You can modify the target regions + and update configurations for individual components. To disable a component, set + its value to null. Only the provided fields will be updated; all others remain + unchanged. + + Args: + project_id: Project ID + + deployment_name: Name of deployment + + api_keys: List of API keys for the application + + components_configuration: Mapping of component names to their configuration (e.g., `"model": {...}`) + + regions: Geographical regions to be updated for the deployment + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return await self._patch( + f"/cloud/v3/inference/applications/{project_id}/deployments/{deployment_name}", + body=await async_maybe_transform( + { + "api_keys": api_keys, + "components_configuration": components_configuration, + "regions": regions, + }, + deployment_update_params.DeploymentUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def list( + self, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceApplicationDeploymentList: + """ + Returns a list of your application deployments, including deployment names, + associated catalog applications, regions, component configurations, and current + status. Useful for monitoring and managing all active AI application instances. + + Args: + project_id: Project ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return await self._get( + f"/cloud/v3/inference/applications/{project_id}/deployments", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceApplicationDeploymentList, + ) + + async def delete( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Deletes an existing application deployment along with all associated resources. + This action will permanently remove the deployment and **terminate all related + inference instances** that are part of the application. + + Args: + project_id: Project ID + + deployment_name: Name of deployment + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return await self._delete( + f"/cloud/v3/inference/applications/{project_id}/deployments/{deployment_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceApplicationDeployment: + """Retrieves detailed information about a specific application deployment. + + The + response includes the catalog application it was created from, deployment name, + active regions, configuration of each component, and the current status of the + deployment. + + Args: + project_id: Project ID + + deployment_name: Name of deployment + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return await self._get( + f"/cloud/v3/inference/applications/{project_id}/deployments/{deployment_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceApplicationDeployment, + ) + + +class DeploymentsResourceWithRawResponse: + def __init__(self, deployments: DeploymentsResource) -> None: + self._deployments = deployments + + self.create = to_raw_response_wrapper( + deployments.create, + ) + self.update = to_raw_response_wrapper( + deployments.update, + ) + self.list = to_raw_response_wrapper( + deployments.list, + ) + self.delete = to_raw_response_wrapper( + deployments.delete, + ) + self.get = to_raw_response_wrapper( + deployments.get, + ) + + +class AsyncDeploymentsResourceWithRawResponse: + def __init__(self, deployments: AsyncDeploymentsResource) -> None: + self._deployments = deployments + + self.create = async_to_raw_response_wrapper( + deployments.create, + ) + self.update = async_to_raw_response_wrapper( + deployments.update, + ) + self.list = async_to_raw_response_wrapper( + deployments.list, + ) + self.delete = async_to_raw_response_wrapper( + deployments.delete, + ) + self.get = async_to_raw_response_wrapper( + deployments.get, + ) + + +class DeploymentsResourceWithStreamingResponse: + def __init__(self, deployments: DeploymentsResource) -> None: + self._deployments = deployments + + self.create = to_streamed_response_wrapper( + deployments.create, + ) + self.update = to_streamed_response_wrapper( + deployments.update, + ) + self.list = to_streamed_response_wrapper( + deployments.list, + ) + self.delete = to_streamed_response_wrapper( + deployments.delete, + ) + self.get = to_streamed_response_wrapper( + deployments.get, + ) + + +class AsyncDeploymentsResourceWithStreamingResponse: + def __init__(self, deployments: AsyncDeploymentsResource) -> None: + self._deployments = deployments + + self.create = async_to_streamed_response_wrapper( + deployments.create, + ) + self.update = async_to_streamed_response_wrapper( + deployments.update, + ) + self.list = async_to_streamed_response_wrapper( + deployments.list, + ) + self.delete = async_to_streamed_response_wrapper( + deployments.delete, + ) + self.get = async_to_streamed_response_wrapper( + deployments.get, + ) diff --git a/src/gcore/resources/cloud/inference/applications/templates.py b/src/gcore/resources/cloud/inference/applications/templates.py new file mode 100644 index 00000000..d888a399 --- /dev/null +++ b/src/gcore/resources/cloud/inference/applications/templates.py @@ -0,0 +1,238 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import Body, Query, Headers, NotGiven, not_given +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.inference.applications.inference_application_template import InferenceApplicationTemplate +from .....types.cloud.inference.applications.inference_application_template_list import InferenceApplicationTemplateList + +__all__ = ["TemplatesResource", "AsyncTemplatesResource"] + + +class TemplatesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> TemplatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return TemplatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TemplatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return TemplatesResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceApplicationTemplateList: + """ + Returns a list of available machine learning application templates from the + catalog. Each template includes metadata such as name, description, cover image, + documentation, tags, and a set of configurable components (e.g., `model`, `ui`). + Components define parameters, supported deployment flavors, and other attributes + required to create a fully functional application deployment. + """ + return self._get( + "/cloud/v3/inference/applications/catalog", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceApplicationTemplateList, + ) + + def get( + self, + application_name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceApplicationTemplate: + """ + Retrieves detailed information about a specific machine learning application + template from the catalog. The response includes the application’s metadata, + documentation, tags, and a complete set of components with configuration + options, compatible flavors, and deployment capabilities — all necessary for + building and customizing an AI application. + + Args: + application_name: Name of application in catalog + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not application_name: + raise ValueError(f"Expected a non-empty value for `application_name` but received {application_name!r}") + return self._get( + f"/cloud/v3/inference/applications/catalog/{application_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceApplicationTemplate, + ) + + +class AsyncTemplatesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncTemplatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncTemplatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTemplatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncTemplatesResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceApplicationTemplateList: + """ + Returns a list of available machine learning application templates from the + catalog. Each template includes metadata such as name, description, cover image, + documentation, tags, and a set of configurable components (e.g., `model`, `ui`). + Components define parameters, supported deployment flavors, and other attributes + required to create a fully functional application deployment. + """ + return await self._get( + "/cloud/v3/inference/applications/catalog", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceApplicationTemplateList, + ) + + async def get( + self, + application_name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceApplicationTemplate: + """ + Retrieves detailed information about a specific machine learning application + template from the catalog. The response includes the application’s metadata, + documentation, tags, and a complete set of components with configuration + options, compatible flavors, and deployment capabilities — all necessary for + building and customizing an AI application. + + Args: + application_name: Name of application in catalog + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not application_name: + raise ValueError(f"Expected a non-empty value for `application_name` but received {application_name!r}") + return await self._get( + f"/cloud/v3/inference/applications/catalog/{application_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceApplicationTemplate, + ) + + +class TemplatesResourceWithRawResponse: + def __init__(self, templates: TemplatesResource) -> None: + self._templates = templates + + self.list = to_raw_response_wrapper( + templates.list, + ) + self.get = to_raw_response_wrapper( + templates.get, + ) + + +class AsyncTemplatesResourceWithRawResponse: + def __init__(self, templates: AsyncTemplatesResource) -> None: + self._templates = templates + + self.list = async_to_raw_response_wrapper( + templates.list, + ) + self.get = async_to_raw_response_wrapper( + templates.get, + ) + + +class TemplatesResourceWithStreamingResponse: + def __init__(self, templates: TemplatesResource) -> None: + self._templates = templates + + self.list = to_streamed_response_wrapper( + templates.list, + ) + self.get = to_streamed_response_wrapper( + templates.get, + ) + + +class AsyncTemplatesResourceWithStreamingResponse: + def __init__(self, templates: AsyncTemplatesResource) -> None: + self._templates = templates + + self.list = async_to_streamed_response_wrapper( + templates.list, + ) + self.get = async_to_streamed_response_wrapper( + templates.get, + ) diff --git a/src/gcore/resources/cloud/inference/deployments/__init__.py b/src/gcore/resources/cloud/inference/deployments/__init__.py new file mode 100644 index 00000000..7386d04f --- /dev/null +++ b/src/gcore/resources/cloud/inference/deployments/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .logs import ( + LogsResource, + AsyncLogsResource, + LogsResourceWithRawResponse, + AsyncLogsResourceWithRawResponse, + LogsResourceWithStreamingResponse, + AsyncLogsResourceWithStreamingResponse, +) +from .deployments import ( + DeploymentsResource, + AsyncDeploymentsResource, + DeploymentsResourceWithRawResponse, + AsyncDeploymentsResourceWithRawResponse, + DeploymentsResourceWithStreamingResponse, + AsyncDeploymentsResourceWithStreamingResponse, +) + +__all__ = [ + "LogsResource", + "AsyncLogsResource", + "LogsResourceWithRawResponse", + "AsyncLogsResourceWithRawResponse", + "LogsResourceWithStreamingResponse", + "AsyncLogsResourceWithStreamingResponse", + "DeploymentsResource", + "AsyncDeploymentsResource", + "DeploymentsResourceWithRawResponse", + "AsyncDeploymentsResourceWithRawResponse", + "DeploymentsResourceWithStreamingResponse", + "AsyncDeploymentsResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/inference/deployments/deployments.py b/src/gcore/resources/cloud/inference/deployments/deployments.py new file mode 100644 index 00000000..caa01442 --- /dev/null +++ b/src/gcore/resources/cloud/inference/deployments/deployments.py @@ -0,0 +1,1231 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import typing_extensions +from typing import Dict, Iterable, Optional + +import httpx + +from .logs import ( + LogsResource, + AsyncLogsResource, + LogsResourceWithRawResponse, + AsyncLogsResourceWithRawResponse, + LogsResourceWithStreamingResponse, + AsyncLogsResourceWithStreamingResponse, +) +from ....._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .....pagination import SyncOffsetPage, AsyncOffsetPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.cloud.inference import deployment_list_params, deployment_create_params, deployment_update_params +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.inference.inference_deployment import InferenceDeployment +from .....types.cloud.inference.inference_deployment_api_key import InferenceDeploymentAPIKey + +__all__ = ["DeploymentsResource", "AsyncDeploymentsResource"] + + +class DeploymentsResource(SyncAPIResource): + @cached_property + def logs(self) -> LogsResource: + return LogsResource(self._client) + + @cached_property + def with_raw_response(self) -> DeploymentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return DeploymentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DeploymentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return DeploymentsResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + containers: Iterable[deployment_create_params.Container], + flavor_name: str, + image: str, + listening_port: int, + name: str, + api_keys: SequenceNotStr[str] | Omit = omit, + auth_enabled: bool | Omit = omit, + command: Optional[SequenceNotStr[str]] | Omit = omit, + credentials_name: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + envs: Dict[str, str] | Omit = omit, + ingress_opts: Optional[deployment_create_params.IngressOpts] | Omit = omit, + logging: Optional[deployment_create_params.Logging] | Omit = omit, + probes: Optional[deployment_create_params.Probes] | Omit = omit, + api_timeout: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create inference deployment + + Args: + project_id: Project ID + + containers: List of containers for the inference instance. + + flavor_name: Flavor name for the inference instance. + + image: Docker image for the inference instance. This field should contain the image + name and tag in the format 'name:tag', e.g., 'nginx:latest'. It defaults to + Docker Hub as the image registry, but any accessible Docker image URL can be + specified. + + listening_port: Listening port for the inference instance. + + name: Inference instance name. + + api_keys: List of API keys for the inference instance. Multiple keys can be attached to + one deployment.If `auth_enabled` and `api_keys` are both specified, a + ValidationError will be raised. + + auth_enabled: Set to `true` to enable API key authentication for the inference instance. + `"Authorization": "Bearer *****"` or `"X-Api-Key": "*****"` header is required + for the requests to the instance if enabled. This field is deprecated and will + be removed in the future. Use `api_keys` field instead.If `auth_enabled` and + `api_keys` are both specified, a ValidationError will be raised. + + command: Command to be executed when running a container from an image. + + credentials_name: Registry credentials name + + description: Inference instance description. + + envs: Environment variables for the inference instance. + + ingress_opts: Ingress options for the inference instance + + logging: Logging configuration for the inference instance + + probes: Probes configured for all containers of the inference instance. If probes are + not provided, and the `image_name` is from a the Model Catalog registry, the + default probes will be used. + + api_timeout: Specifies the duration in seconds without any requests after which the + containers will be downscaled to their minimum scale value as defined by + `scale.min`. If set, this helps in optimizing resource usage by reducing the + number of container instances during periods of inactivity. The default value + when the parameter is not set is 120. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._post( + f"/cloud/v3/inference/{project_id}/deployments", + body=maybe_transform( + { + "containers": containers, + "flavor_name": flavor_name, + "image": image, + "listening_port": listening_port, + "name": name, + "api_keys": api_keys, + "auth_enabled": auth_enabled, + "command": command, + "credentials_name": credentials_name, + "description": description, + "envs": envs, + "ingress_opts": ingress_opts, + "logging": logging, + "probes": probes, + "api_timeout": api_timeout, + }, + deployment_create_params.DeploymentCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + deployment_name: str, + *, + project_id: int | None = None, + api_keys: Optional[SequenceNotStr[str]] | Omit = omit, + auth_enabled: bool | Omit = omit, + command: Optional[SequenceNotStr[str]] | Omit = omit, + containers: Optional[Iterable[deployment_update_params.Container]] | Omit = omit, + credentials_name: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + envs: Optional[Dict[str, str]] | Omit = omit, + flavor_name: str | Omit = omit, + image: Optional[str] | Omit = omit, + ingress_opts: Optional[deployment_update_params.IngressOpts] | Omit = omit, + listening_port: Optional[int] | Omit = omit, + logging: Optional[deployment_update_params.Logging] | Omit = omit, + probes: Optional[deployment_update_params.Probes] | Omit = omit, + api_timeout: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Update inference deployment + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + api_keys: List of API keys for the inference instance. Multiple keys can be attached to + one deployment.If `auth_enabled` and `api_keys` are both specified, a + ValidationError will be raised.If `[]` is provided, the API keys will be removed + and auth will be disabled on the deployment. + + auth_enabled: Set to `true` to enable API key authentication for the inference instance. + `"Authorization": "Bearer *****"` or `"X-Api-Key": "*****"` header is required + for the requests to the instance if enabled. This field is deprecated and will + be removed in the future. Use `api_keys` field instead.If `auth_enabled` and + `api_keys` are both specified, a ValidationError will be raised. + + command: Command to be executed when running a container from an image. + + containers: List of containers for the inference instance. + + credentials_name: Registry credentials name + + description: Inference instance description. + + envs: Environment variables for the inference instance. + + flavor_name: Flavor name for the inference instance. + + image: Docker image for the inference instance. This field should contain the image + name and tag in the format 'name:tag', e.g., 'nginx:latest'. It defaults to + Docker Hub as the image registry, but any accessible Docker image URL can be + specified. + + ingress_opts: Ingress options for the inference instance + + listening_port: Listening port for the inference instance. + + logging: Logging configuration for the inference instance + + probes: Probes configured for all containers of the inference instance. + + api_timeout: Specifies the duration in seconds without any requests after which the + containers will be downscaled to their minimum scale value as defined by + `scale.min`. If set, this helps in optimizing resource usage by reducing the + number of container instances during periods of inactivity. The default value + when the parameter is not set is 120. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return self._patch( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}", + body=maybe_transform( + { + "api_keys": api_keys, + "auth_enabled": auth_enabled, + "command": command, + "containers": containers, + "credentials_name": credentials_name, + "description": description, + "envs": envs, + "flavor_name": flavor_name, + "image": image, + "ingress_opts": ingress_opts, + "listening_port": listening_port, + "logging": logging, + "probes": probes, + "api_timeout": api_timeout, + }, + deployment_update_params.DeploymentUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[InferenceDeployment]: + """List inference deployments + + Args: + project_id: Project ID + + limit: Optional. + + Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._get_api_list( + f"/cloud/v3/inference/{project_id}/deployments", + page=SyncOffsetPage[InferenceDeployment], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + deployment_list_params.DeploymentListParams, + ), + ), + model=InferenceDeployment, + ) + + def delete( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete inference deployment + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return self._delete( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceDeployment: + """ + Get inference deployment + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return self._get( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceDeployment, + ) + + @typing_extensions.deprecated("deprecated") + def get_api_key( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceDeploymentAPIKey: + """ + Get inference deployment API key + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return self._get( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}/apikey", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceDeploymentAPIKey, + ) + + def start( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + This operation initializes an inference deployment after it was stopped, making + it available to handle inference requests again. The instance will launch with + the **minimum** number of replicas defined in the scaling settings. + + - If the minimum replicas are set to **0**, the instance will initially start + with **0** replicas. + - It will automatically scale up when it receives requests or SQS messages, + according to the configured scaling rules. + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}/start", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def stop( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + This operation shuts down an inference deployment, making it unavailable for + handling requests. The deployment will scale down to **0** replicas, overriding + any minimum replica settings. + + - Once stopped, the deployment will **not** process any inference requests or + SQS messages. + - It will **not** restart automatically and must be started manually. + - While stopped, the deployment will **not** incur any charges. + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}/stop", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncDeploymentsResource(AsyncAPIResource): + @cached_property + def logs(self) -> AsyncLogsResource: + return AsyncLogsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncDeploymentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncDeploymentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDeploymentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncDeploymentsResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + containers: Iterable[deployment_create_params.Container], + flavor_name: str, + image: str, + listening_port: int, + name: str, + api_keys: SequenceNotStr[str] | Omit = omit, + auth_enabled: bool | Omit = omit, + command: Optional[SequenceNotStr[str]] | Omit = omit, + credentials_name: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + envs: Dict[str, str] | Omit = omit, + ingress_opts: Optional[deployment_create_params.IngressOpts] | Omit = omit, + logging: Optional[deployment_create_params.Logging] | Omit = omit, + probes: Optional[deployment_create_params.Probes] | Omit = omit, + api_timeout: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create inference deployment + + Args: + project_id: Project ID + + containers: List of containers for the inference instance. + + flavor_name: Flavor name for the inference instance. + + image: Docker image for the inference instance. This field should contain the image + name and tag in the format 'name:tag', e.g., 'nginx:latest'. It defaults to + Docker Hub as the image registry, but any accessible Docker image URL can be + specified. + + listening_port: Listening port for the inference instance. + + name: Inference instance name. + + api_keys: List of API keys for the inference instance. Multiple keys can be attached to + one deployment.If `auth_enabled` and `api_keys` are both specified, a + ValidationError will be raised. + + auth_enabled: Set to `true` to enable API key authentication for the inference instance. + `"Authorization": "Bearer *****"` or `"X-Api-Key": "*****"` header is required + for the requests to the instance if enabled. This field is deprecated and will + be removed in the future. Use `api_keys` field instead.If `auth_enabled` and + `api_keys` are both specified, a ValidationError will be raised. + + command: Command to be executed when running a container from an image. + + credentials_name: Registry credentials name + + description: Inference instance description. + + envs: Environment variables for the inference instance. + + ingress_opts: Ingress options for the inference instance + + logging: Logging configuration for the inference instance + + probes: Probes configured for all containers of the inference instance. If probes are + not provided, and the `image_name` is from a the Model Catalog registry, the + default probes will be used. + + api_timeout: Specifies the duration in seconds without any requests after which the + containers will be downscaled to their minimum scale value as defined by + `scale.min`. If set, this helps in optimizing resource usage by reducing the + number of container instances during periods of inactivity. The default value + when the parameter is not set is 120. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return await self._post( + f"/cloud/v3/inference/{project_id}/deployments", + body=await async_maybe_transform( + { + "containers": containers, + "flavor_name": flavor_name, + "image": image, + "listening_port": listening_port, + "name": name, + "api_keys": api_keys, + "auth_enabled": auth_enabled, + "command": command, + "credentials_name": credentials_name, + "description": description, + "envs": envs, + "ingress_opts": ingress_opts, + "logging": logging, + "probes": probes, + "api_timeout": api_timeout, + }, + deployment_create_params.DeploymentCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + deployment_name: str, + *, + project_id: int | None = None, + api_keys: Optional[SequenceNotStr[str]] | Omit = omit, + auth_enabled: bool | Omit = omit, + command: Optional[SequenceNotStr[str]] | Omit = omit, + containers: Optional[Iterable[deployment_update_params.Container]] | Omit = omit, + credentials_name: Optional[str] | Omit = omit, + description: Optional[str] | Omit = omit, + envs: Optional[Dict[str, str]] | Omit = omit, + flavor_name: str | Omit = omit, + image: Optional[str] | Omit = omit, + ingress_opts: Optional[deployment_update_params.IngressOpts] | Omit = omit, + listening_port: Optional[int] | Omit = omit, + logging: Optional[deployment_update_params.Logging] | Omit = omit, + probes: Optional[deployment_update_params.Probes] | Omit = omit, + api_timeout: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Update inference deployment + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + api_keys: List of API keys for the inference instance. Multiple keys can be attached to + one deployment.If `auth_enabled` and `api_keys` are both specified, a + ValidationError will be raised.If `[]` is provided, the API keys will be removed + and auth will be disabled on the deployment. + + auth_enabled: Set to `true` to enable API key authentication for the inference instance. + `"Authorization": "Bearer *****"` or `"X-Api-Key": "*****"` header is required + for the requests to the instance if enabled. This field is deprecated and will + be removed in the future. Use `api_keys` field instead.If `auth_enabled` and + `api_keys` are both specified, a ValidationError will be raised. + + command: Command to be executed when running a container from an image. + + containers: List of containers for the inference instance. + + credentials_name: Registry credentials name + + description: Inference instance description. + + envs: Environment variables for the inference instance. + + flavor_name: Flavor name for the inference instance. + + image: Docker image for the inference instance. This field should contain the image + name and tag in the format 'name:tag', e.g., 'nginx:latest'. It defaults to + Docker Hub as the image registry, but any accessible Docker image URL can be + specified. + + ingress_opts: Ingress options for the inference instance + + listening_port: Listening port for the inference instance. + + logging: Logging configuration for the inference instance + + probes: Probes configured for all containers of the inference instance. + + api_timeout: Specifies the duration in seconds without any requests after which the + containers will be downscaled to their minimum scale value as defined by + `scale.min`. If set, this helps in optimizing resource usage by reducing the + number of container instances during periods of inactivity. The default value + when the parameter is not set is 120. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return await self._patch( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}", + body=await async_maybe_transform( + { + "api_keys": api_keys, + "auth_enabled": auth_enabled, + "command": command, + "containers": containers, + "credentials_name": credentials_name, + "description": description, + "envs": envs, + "flavor_name": flavor_name, + "image": image, + "ingress_opts": ingress_opts, + "listening_port": listening_port, + "logging": logging, + "probes": probes, + "api_timeout": api_timeout, + }, + deployment_update_params.DeploymentUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[InferenceDeployment, AsyncOffsetPage[InferenceDeployment]]: + """List inference deployments + + Args: + project_id: Project ID + + limit: Optional. + + Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._get_api_list( + f"/cloud/v3/inference/{project_id}/deployments", + page=AsyncOffsetPage[InferenceDeployment], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + deployment_list_params.DeploymentListParams, + ), + ), + model=InferenceDeployment, + ) + + async def delete( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete inference deployment + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return await self._delete( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceDeployment: + """ + Get inference deployment + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return await self._get( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceDeployment, + ) + + @typing_extensions.deprecated("deprecated") + async def get_api_key( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceDeploymentAPIKey: + """ + Get inference deployment API key + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return await self._get( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}/apikey", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceDeploymentAPIKey, + ) + + async def start( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + This operation initializes an inference deployment after it was stopped, making + it available to handle inference requests again. The instance will launch with + the **minimum** number of replicas defined in the scaling settings. + + - If the minimum replicas are set to **0**, the instance will initially start + with **0** replicas. + - It will automatically scale up when it receives requests or SQS messages, + according to the configured scaling rules. + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}/start", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def stop( + self, + deployment_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + This operation shuts down an inference deployment, making it unavailable for + handling requests. The deployment will scale down to **0** replicas, overriding + any minimum replica settings. + + - Once stopped, the deployment will **not** process any inference requests or + SQS messages. + - It will **not** restart automatically and must be started manually. + - While stopped, the deployment will **not** incur any charges. + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}/stop", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class DeploymentsResourceWithRawResponse: + def __init__(self, deployments: DeploymentsResource) -> None: + self._deployments = deployments + + self.create = to_raw_response_wrapper( + deployments.create, + ) + self.update = to_raw_response_wrapper( + deployments.update, + ) + self.list = to_raw_response_wrapper( + deployments.list, + ) + self.delete = to_raw_response_wrapper( + deployments.delete, + ) + self.get = to_raw_response_wrapper( + deployments.get, + ) + self.get_api_key = ( # pyright: ignore[reportDeprecated] + to_raw_response_wrapper( + deployments.get_api_key, # pyright: ignore[reportDeprecated], + ) + ) + self.start = to_raw_response_wrapper( + deployments.start, + ) + self.stop = to_raw_response_wrapper( + deployments.stop, + ) + + @cached_property + def logs(self) -> LogsResourceWithRawResponse: + return LogsResourceWithRawResponse(self._deployments.logs) + + +class AsyncDeploymentsResourceWithRawResponse: + def __init__(self, deployments: AsyncDeploymentsResource) -> None: + self._deployments = deployments + + self.create = async_to_raw_response_wrapper( + deployments.create, + ) + self.update = async_to_raw_response_wrapper( + deployments.update, + ) + self.list = async_to_raw_response_wrapper( + deployments.list, + ) + self.delete = async_to_raw_response_wrapper( + deployments.delete, + ) + self.get = async_to_raw_response_wrapper( + deployments.get, + ) + self.get_api_key = ( # pyright: ignore[reportDeprecated] + async_to_raw_response_wrapper( + deployments.get_api_key, # pyright: ignore[reportDeprecated], + ) + ) + self.start = async_to_raw_response_wrapper( + deployments.start, + ) + self.stop = async_to_raw_response_wrapper( + deployments.stop, + ) + + @cached_property + def logs(self) -> AsyncLogsResourceWithRawResponse: + return AsyncLogsResourceWithRawResponse(self._deployments.logs) + + +class DeploymentsResourceWithStreamingResponse: + def __init__(self, deployments: DeploymentsResource) -> None: + self._deployments = deployments + + self.create = to_streamed_response_wrapper( + deployments.create, + ) + self.update = to_streamed_response_wrapper( + deployments.update, + ) + self.list = to_streamed_response_wrapper( + deployments.list, + ) + self.delete = to_streamed_response_wrapper( + deployments.delete, + ) + self.get = to_streamed_response_wrapper( + deployments.get, + ) + self.get_api_key = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + deployments.get_api_key, # pyright: ignore[reportDeprecated], + ) + ) + self.start = to_streamed_response_wrapper( + deployments.start, + ) + self.stop = to_streamed_response_wrapper( + deployments.stop, + ) + + @cached_property + def logs(self) -> LogsResourceWithStreamingResponse: + return LogsResourceWithStreamingResponse(self._deployments.logs) + + +class AsyncDeploymentsResourceWithStreamingResponse: + def __init__(self, deployments: AsyncDeploymentsResource) -> None: + self._deployments = deployments + + self.create = async_to_streamed_response_wrapper( + deployments.create, + ) + self.update = async_to_streamed_response_wrapper( + deployments.update, + ) + self.list = async_to_streamed_response_wrapper( + deployments.list, + ) + self.delete = async_to_streamed_response_wrapper( + deployments.delete, + ) + self.get = async_to_streamed_response_wrapper( + deployments.get, + ) + self.get_api_key = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + deployments.get_api_key, # pyright: ignore[reportDeprecated], + ) + ) + self.start = async_to_streamed_response_wrapper( + deployments.start, + ) + self.stop = async_to_streamed_response_wrapper( + deployments.stop, + ) + + @cached_property + def logs(self) -> AsyncLogsResourceWithStreamingResponse: + return AsyncLogsResourceWithStreamingResponse(self._deployments.logs) diff --git a/src/gcore/resources/cloud/inference/deployments/logs.py b/src/gcore/resources/cloud/inference/deployments/logs.py new file mode 100644 index 00000000..3a46cbd0 --- /dev/null +++ b/src/gcore/resources/cloud/inference/deployments/logs.py @@ -0,0 +1,235 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .....pagination import SyncOffsetPage, AsyncOffsetPage +from ....._base_client import AsyncPaginator, make_request_options +from .....types.cloud.inference.deployments import log_list_params +from .....types.cloud.inference.deployments.inference_deployment_log import InferenceDeploymentLog + +__all__ = ["LogsResource", "AsyncLogsResource"] + + +class LogsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> LogsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return LogsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> LogsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return LogsResourceWithStreamingResponse(self) + + def list( + self, + deployment_name: str, + *, + project_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["time.asc", "time.desc"] | Omit = omit, + region_id: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[InferenceDeploymentLog]: + """ + Get inference deployment logs + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + order_by: Order by field + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return self._get_api_list( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}/logs", + page=SyncOffsetPage[InferenceDeploymentLog], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + "order_by": order_by, + "region_id": region_id, + }, + log_list_params.LogListParams, + ), + ), + model=InferenceDeploymentLog, + ) + + +class AsyncLogsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncLogsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncLogsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncLogsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncLogsResourceWithStreamingResponse(self) + + def list( + self, + deployment_name: str, + *, + project_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["time.asc", "time.desc"] | Omit = omit, + region_id: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[InferenceDeploymentLog, AsyncOffsetPage[InferenceDeploymentLog]]: + """ + Get inference deployment logs + + Args: + project_id: Project ID + + deployment_name: Inference instance name. + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + order_by: Order by field + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not deployment_name: + raise ValueError(f"Expected a non-empty value for `deployment_name` but received {deployment_name!r}") + return self._get_api_list( + f"/cloud/v3/inference/{project_id}/deployments/{deployment_name}/logs", + page=AsyncOffsetPage[InferenceDeploymentLog], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + "order_by": order_by, + "region_id": region_id, + }, + log_list_params.LogListParams, + ), + ), + model=InferenceDeploymentLog, + ) + + +class LogsResourceWithRawResponse: + def __init__(self, logs: LogsResource) -> None: + self._logs = logs + + self.list = to_raw_response_wrapper( + logs.list, + ) + + +class AsyncLogsResourceWithRawResponse: + def __init__(self, logs: AsyncLogsResource) -> None: + self._logs = logs + + self.list = async_to_raw_response_wrapper( + logs.list, + ) + + +class LogsResourceWithStreamingResponse: + def __init__(self, logs: LogsResource) -> None: + self._logs = logs + + self.list = to_streamed_response_wrapper( + logs.list, + ) + + +class AsyncLogsResourceWithStreamingResponse: + def __init__(self, logs: AsyncLogsResource) -> None: + self._logs = logs + + self.list = async_to_streamed_response_wrapper( + logs.list, + ) diff --git a/src/gcore/resources/cloud/inference/flavors.py b/src/gcore/resources/cloud/inference/flavors.py new file mode 100644 index 00000000..c9934320 --- /dev/null +++ b/src/gcore/resources/cloud/inference/flavors.py @@ -0,0 +1,280 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.inference import flavor_list_params +from ....types.cloud.inference.inference_flavor import InferenceFlavor + +__all__ = ["FlavorsResource", "AsyncFlavorsResource"] + + +class FlavorsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> FlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return FlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return FlavorsResourceWithStreamingResponse(self) + + def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[InferenceFlavor]: + """List inference flavors + + Args: + limit: Optional. + + Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v3/inference/flavors", + page=SyncOffsetPage[InferenceFlavor], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + flavor_list_params.FlavorListParams, + ), + ), + model=InferenceFlavor, + ) + + def get( + self, + flavor_name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceFlavor: + """ + Get inference flavor + + Args: + flavor_name: Inference flavor name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not flavor_name: + raise ValueError(f"Expected a non-empty value for `flavor_name` but received {flavor_name!r}") + return self._get( + f"/cloud/v3/inference/flavors/{flavor_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceFlavor, + ) + + +class AsyncFlavorsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncFlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncFlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncFlavorsResourceWithStreamingResponse(self) + + def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[InferenceFlavor, AsyncOffsetPage[InferenceFlavor]]: + """List inference flavors + + Args: + limit: Optional. + + Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v3/inference/flavors", + page=AsyncOffsetPage[InferenceFlavor], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + flavor_list_params.FlavorListParams, + ), + ), + model=InferenceFlavor, + ) + + async def get( + self, + flavor_name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceFlavor: + """ + Get inference flavor + + Args: + flavor_name: Inference flavor name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not flavor_name: + raise ValueError(f"Expected a non-empty value for `flavor_name` but received {flavor_name!r}") + return await self._get( + f"/cloud/v3/inference/flavors/{flavor_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceFlavor, + ) + + +class FlavorsResourceWithRawResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_raw_response_wrapper( + flavors.list, + ) + self.get = to_raw_response_wrapper( + flavors.get, + ) + + +class AsyncFlavorsResourceWithRawResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_raw_response_wrapper( + flavors.list, + ) + self.get = async_to_raw_response_wrapper( + flavors.get, + ) + + +class FlavorsResourceWithStreamingResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_streamed_response_wrapper( + flavors.list, + ) + self.get = to_streamed_response_wrapper( + flavors.get, + ) + + +class AsyncFlavorsResourceWithStreamingResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_streamed_response_wrapper( + flavors.list, + ) + self.get = async_to_streamed_response_wrapper( + flavors.get, + ) diff --git a/src/gcore/resources/cloud/inference/inference.py b/src/gcore/resources/cloud/inference/inference.py new file mode 100644 index 00000000..86dd2f3c --- /dev/null +++ b/src/gcore/resources/cloud/inference/inference.py @@ -0,0 +1,327 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from .secrets import ( + SecretsResource, + AsyncSecretsResource, + SecretsResourceWithRawResponse, + AsyncSecretsResourceWithRawResponse, + SecretsResourceWithStreamingResponse, + AsyncSecretsResourceWithStreamingResponse, +) +from .api_keys import ( + APIKeysResource, + AsyncAPIKeysResource, + APIKeysResourceWithRawResponse, + AsyncAPIKeysResourceWithRawResponse, + APIKeysResourceWithStreamingResponse, + AsyncAPIKeysResourceWithStreamingResponse, +) +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from .registry_credentials import ( + RegistryCredentialsResource, + AsyncRegistryCredentialsResource, + RegistryCredentialsResourceWithRawResponse, + AsyncRegistryCredentialsResourceWithRawResponse, + RegistryCredentialsResourceWithStreamingResponse, + AsyncRegistryCredentialsResourceWithStreamingResponse, +) +from .deployments.deployments import ( + DeploymentsResource, + AsyncDeploymentsResource, + DeploymentsResourceWithRawResponse, + AsyncDeploymentsResourceWithRawResponse, + DeploymentsResourceWithStreamingResponse, + AsyncDeploymentsResourceWithStreamingResponse, +) +from .applications.applications import ( + ApplicationsResource, + AsyncApplicationsResource, + ApplicationsResourceWithRawResponse, + AsyncApplicationsResourceWithRawResponse, + ApplicationsResourceWithStreamingResponse, + AsyncApplicationsResourceWithStreamingResponse, +) +from ....types.cloud.inference_region_capacity_list import InferenceRegionCapacityList + +__all__ = ["InferenceResource", "AsyncInferenceResource"] + + +class InferenceResource(SyncAPIResource): + @cached_property + def flavors(self) -> FlavorsResource: + return FlavorsResource(self._client) + + @cached_property + def deployments(self) -> DeploymentsResource: + return DeploymentsResource(self._client) + + @cached_property + def registry_credentials(self) -> RegistryCredentialsResource: + return RegistryCredentialsResource(self._client) + + @cached_property + def secrets(self) -> SecretsResource: + return SecretsResource(self._client) + + @cached_property + def api_keys(self) -> APIKeysResource: + return APIKeysResource(self._client) + + @cached_property + def applications(self) -> ApplicationsResource: + return ApplicationsResource(self._client) + + @cached_property + def with_raw_response(self) -> InferenceResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return InferenceResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InferenceResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return InferenceResourceWithStreamingResponse(self) + + def get_capacity_by_region( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceRegionCapacityList: + """Get inference capacity by region""" + return self._get( + "/cloud/v3/inference/capacity", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceRegionCapacityList, + ) + + +class AsyncInferenceResource(AsyncAPIResource): + @cached_property + def flavors(self) -> AsyncFlavorsResource: + return AsyncFlavorsResource(self._client) + + @cached_property + def deployments(self) -> AsyncDeploymentsResource: + return AsyncDeploymentsResource(self._client) + + @cached_property + def registry_credentials(self) -> AsyncRegistryCredentialsResource: + return AsyncRegistryCredentialsResource(self._client) + + @cached_property + def secrets(self) -> AsyncSecretsResource: + return AsyncSecretsResource(self._client) + + @cached_property + def api_keys(self) -> AsyncAPIKeysResource: + return AsyncAPIKeysResource(self._client) + + @cached_property + def applications(self) -> AsyncApplicationsResource: + return AsyncApplicationsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncInferenceResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncInferenceResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInferenceResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncInferenceResourceWithStreamingResponse(self) + + async def get_capacity_by_region( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceRegionCapacityList: + """Get inference capacity by region""" + return await self._get( + "/cloud/v3/inference/capacity", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceRegionCapacityList, + ) + + +class InferenceResourceWithRawResponse: + def __init__(self, inference: InferenceResource) -> None: + self._inference = inference + + self.get_capacity_by_region = to_raw_response_wrapper( + inference.get_capacity_by_region, + ) + + @cached_property + def flavors(self) -> FlavorsResourceWithRawResponse: + return FlavorsResourceWithRawResponse(self._inference.flavors) + + @cached_property + def deployments(self) -> DeploymentsResourceWithRawResponse: + return DeploymentsResourceWithRawResponse(self._inference.deployments) + + @cached_property + def registry_credentials(self) -> RegistryCredentialsResourceWithRawResponse: + return RegistryCredentialsResourceWithRawResponse(self._inference.registry_credentials) + + @cached_property + def secrets(self) -> SecretsResourceWithRawResponse: + return SecretsResourceWithRawResponse(self._inference.secrets) + + @cached_property + def api_keys(self) -> APIKeysResourceWithRawResponse: + return APIKeysResourceWithRawResponse(self._inference.api_keys) + + @cached_property + def applications(self) -> ApplicationsResourceWithRawResponse: + return ApplicationsResourceWithRawResponse(self._inference.applications) + + +class AsyncInferenceResourceWithRawResponse: + def __init__(self, inference: AsyncInferenceResource) -> None: + self._inference = inference + + self.get_capacity_by_region = async_to_raw_response_wrapper( + inference.get_capacity_by_region, + ) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithRawResponse: + return AsyncFlavorsResourceWithRawResponse(self._inference.flavors) + + @cached_property + def deployments(self) -> AsyncDeploymentsResourceWithRawResponse: + return AsyncDeploymentsResourceWithRawResponse(self._inference.deployments) + + @cached_property + def registry_credentials(self) -> AsyncRegistryCredentialsResourceWithRawResponse: + return AsyncRegistryCredentialsResourceWithRawResponse(self._inference.registry_credentials) + + @cached_property + def secrets(self) -> AsyncSecretsResourceWithRawResponse: + return AsyncSecretsResourceWithRawResponse(self._inference.secrets) + + @cached_property + def api_keys(self) -> AsyncAPIKeysResourceWithRawResponse: + return AsyncAPIKeysResourceWithRawResponse(self._inference.api_keys) + + @cached_property + def applications(self) -> AsyncApplicationsResourceWithRawResponse: + return AsyncApplicationsResourceWithRawResponse(self._inference.applications) + + +class InferenceResourceWithStreamingResponse: + def __init__(self, inference: InferenceResource) -> None: + self._inference = inference + + self.get_capacity_by_region = to_streamed_response_wrapper( + inference.get_capacity_by_region, + ) + + @cached_property + def flavors(self) -> FlavorsResourceWithStreamingResponse: + return FlavorsResourceWithStreamingResponse(self._inference.flavors) + + @cached_property + def deployments(self) -> DeploymentsResourceWithStreamingResponse: + return DeploymentsResourceWithStreamingResponse(self._inference.deployments) + + @cached_property + def registry_credentials(self) -> RegistryCredentialsResourceWithStreamingResponse: + return RegistryCredentialsResourceWithStreamingResponse(self._inference.registry_credentials) + + @cached_property + def secrets(self) -> SecretsResourceWithStreamingResponse: + return SecretsResourceWithStreamingResponse(self._inference.secrets) + + @cached_property + def api_keys(self) -> APIKeysResourceWithStreamingResponse: + return APIKeysResourceWithStreamingResponse(self._inference.api_keys) + + @cached_property + def applications(self) -> ApplicationsResourceWithStreamingResponse: + return ApplicationsResourceWithStreamingResponse(self._inference.applications) + + +class AsyncInferenceResourceWithStreamingResponse: + def __init__(self, inference: AsyncInferenceResource) -> None: + self._inference = inference + + self.get_capacity_by_region = async_to_streamed_response_wrapper( + inference.get_capacity_by_region, + ) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithStreamingResponse: + return AsyncFlavorsResourceWithStreamingResponse(self._inference.flavors) + + @cached_property + def deployments(self) -> AsyncDeploymentsResourceWithStreamingResponse: + return AsyncDeploymentsResourceWithStreamingResponse(self._inference.deployments) + + @cached_property + def registry_credentials(self) -> AsyncRegistryCredentialsResourceWithStreamingResponse: + return AsyncRegistryCredentialsResourceWithStreamingResponse(self._inference.registry_credentials) + + @cached_property + def secrets(self) -> AsyncSecretsResourceWithStreamingResponse: + return AsyncSecretsResourceWithStreamingResponse(self._inference.secrets) + + @cached_property + def api_keys(self) -> AsyncAPIKeysResourceWithStreamingResponse: + return AsyncAPIKeysResourceWithStreamingResponse(self._inference.api_keys) + + @cached_property + def applications(self) -> AsyncApplicationsResourceWithStreamingResponse: + return AsyncApplicationsResourceWithStreamingResponse(self._inference.applications) diff --git a/src/gcore/resources/cloud/inference/registry_credentials.py b/src/gcore/resources/cloud/inference/registry_credentials.py new file mode 100644 index 00000000..c34dfc0a --- /dev/null +++ b/src/gcore/resources/cloud/inference/registry_credentials.py @@ -0,0 +1,646 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.inference import ( + registry_credential_list_params, + registry_credential_create_params, + registry_credential_replace_params, +) +from ....types.cloud.inference.inference_registry_credentials import InferenceRegistryCredentials + +__all__ = ["RegistryCredentialsResource", "AsyncRegistryCredentialsResource"] + + +class RegistryCredentialsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RegistryCredentialsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return RegistryCredentialsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RegistryCredentialsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return RegistryCredentialsResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + name: str, + password: str, + registry_url: str, + username: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceRegistryCredentials: + """ + Create inference registry credential + + Args: + project_id: Project ID + + name: Registry credential name. + + password: Registry password. + + registry_url: Registry URL. + + username: Registry username. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._post( + f"/cloud/v3/inference/{project_id}/registry_credentials", + body=maybe_transform( + { + "name": name, + "password": password, + "registry_url": registry_url, + "username": username, + }, + registry_credential_create_params.RegistryCredentialCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceRegistryCredentials, + ) + + def list( + self, + *, + project_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[InferenceRegistryCredentials]: + """ + List inference registry credentials + + Args: + project_id: Project ID + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._get_api_list( + f"/cloud/v3/inference/{project_id}/registry_credentials", + page=SyncOffsetPage[InferenceRegistryCredentials], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + registry_credential_list_params.RegistryCredentialListParams, + ), + ), + model=InferenceRegistryCredentials, + ) + + def delete( + self, + credential_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete inference registry credential + + Args: + project_id: Project ID + + credential_name: Registry credential name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not credential_name: + raise ValueError(f"Expected a non-empty value for `credential_name` but received {credential_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v3/inference/{project_id}/registry_credentials/{credential_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + credential_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceRegistryCredentials: + """ + Get inference registry credential + + Args: + project_id: Project ID + + credential_name: Registry credential name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not credential_name: + raise ValueError(f"Expected a non-empty value for `credential_name` but received {credential_name!r}") + return self._get( + f"/cloud/v3/inference/{project_id}/registry_credentials/{credential_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceRegistryCredentials, + ) + + def replace( + self, + credential_name: str, + *, + project_id: int | None = None, + password: str, + registry_url: str, + username: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceRegistryCredentials: + """ + Replace inference registry credential + + Args: + project_id: Project ID + + credential_name: Registry credential name. + + password: Registry password. + + registry_url: Registry URL. + + username: Registry username. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not credential_name: + raise ValueError(f"Expected a non-empty value for `credential_name` but received {credential_name!r}") + return self._put( + f"/cloud/v3/inference/{project_id}/registry_credentials/{credential_name}", + body=maybe_transform( + { + "password": password, + "registry_url": registry_url, + "username": username, + }, + registry_credential_replace_params.RegistryCredentialReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceRegistryCredentials, + ) + + +class AsyncRegistryCredentialsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRegistryCredentialsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncRegistryCredentialsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRegistryCredentialsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncRegistryCredentialsResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + name: str, + password: str, + registry_url: str, + username: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceRegistryCredentials: + """ + Create inference registry credential + + Args: + project_id: Project ID + + name: Registry credential name. + + password: Registry password. + + registry_url: Registry URL. + + username: Registry username. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return await self._post( + f"/cloud/v3/inference/{project_id}/registry_credentials", + body=await async_maybe_transform( + { + "name": name, + "password": password, + "registry_url": registry_url, + "username": username, + }, + registry_credential_create_params.RegistryCredentialCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceRegistryCredentials, + ) + + def list( + self, + *, + project_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[InferenceRegistryCredentials, AsyncOffsetPage[InferenceRegistryCredentials]]: + """ + List inference registry credentials + + Args: + project_id: Project ID + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._get_api_list( + f"/cloud/v3/inference/{project_id}/registry_credentials", + page=AsyncOffsetPage[InferenceRegistryCredentials], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + registry_credential_list_params.RegistryCredentialListParams, + ), + ), + model=InferenceRegistryCredentials, + ) + + async def delete( + self, + credential_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete inference registry credential + + Args: + project_id: Project ID + + credential_name: Registry credential name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not credential_name: + raise ValueError(f"Expected a non-empty value for `credential_name` but received {credential_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v3/inference/{project_id}/registry_credentials/{credential_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + credential_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceRegistryCredentials: + """ + Get inference registry credential + + Args: + project_id: Project ID + + credential_name: Registry credential name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not credential_name: + raise ValueError(f"Expected a non-empty value for `credential_name` but received {credential_name!r}") + return await self._get( + f"/cloud/v3/inference/{project_id}/registry_credentials/{credential_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceRegistryCredentials, + ) + + async def replace( + self, + credential_name: str, + *, + project_id: int | None = None, + password: str, + registry_url: str, + username: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceRegistryCredentials: + """ + Replace inference registry credential + + Args: + project_id: Project ID + + credential_name: Registry credential name. + + password: Registry password. + + registry_url: Registry URL. + + username: Registry username. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not credential_name: + raise ValueError(f"Expected a non-empty value for `credential_name` but received {credential_name!r}") + return await self._put( + f"/cloud/v3/inference/{project_id}/registry_credentials/{credential_name}", + body=await async_maybe_transform( + { + "password": password, + "registry_url": registry_url, + "username": username, + }, + registry_credential_replace_params.RegistryCredentialReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceRegistryCredentials, + ) + + +class RegistryCredentialsResourceWithRawResponse: + def __init__(self, registry_credentials: RegistryCredentialsResource) -> None: + self._registry_credentials = registry_credentials + + self.create = to_raw_response_wrapper( + registry_credentials.create, + ) + self.list = to_raw_response_wrapper( + registry_credentials.list, + ) + self.delete = to_raw_response_wrapper( + registry_credentials.delete, + ) + self.get = to_raw_response_wrapper( + registry_credentials.get, + ) + self.replace = to_raw_response_wrapper( + registry_credentials.replace, + ) + + +class AsyncRegistryCredentialsResourceWithRawResponse: + def __init__(self, registry_credentials: AsyncRegistryCredentialsResource) -> None: + self._registry_credentials = registry_credentials + + self.create = async_to_raw_response_wrapper( + registry_credentials.create, + ) + self.list = async_to_raw_response_wrapper( + registry_credentials.list, + ) + self.delete = async_to_raw_response_wrapper( + registry_credentials.delete, + ) + self.get = async_to_raw_response_wrapper( + registry_credentials.get, + ) + self.replace = async_to_raw_response_wrapper( + registry_credentials.replace, + ) + + +class RegistryCredentialsResourceWithStreamingResponse: + def __init__(self, registry_credentials: RegistryCredentialsResource) -> None: + self._registry_credentials = registry_credentials + + self.create = to_streamed_response_wrapper( + registry_credentials.create, + ) + self.list = to_streamed_response_wrapper( + registry_credentials.list, + ) + self.delete = to_streamed_response_wrapper( + registry_credentials.delete, + ) + self.get = to_streamed_response_wrapper( + registry_credentials.get, + ) + self.replace = to_streamed_response_wrapper( + registry_credentials.replace, + ) + + +class AsyncRegistryCredentialsResourceWithStreamingResponse: + def __init__(self, registry_credentials: AsyncRegistryCredentialsResource) -> None: + self._registry_credentials = registry_credentials + + self.create = async_to_streamed_response_wrapper( + registry_credentials.create, + ) + self.list = async_to_streamed_response_wrapper( + registry_credentials.list, + ) + self.delete = async_to_streamed_response_wrapper( + registry_credentials.delete, + ) + self.get = async_to_streamed_response_wrapper( + registry_credentials.get, + ) + self.replace = async_to_streamed_response_wrapper( + registry_credentials.replace, + ) diff --git a/src/gcore/resources/cloud/inference/secrets.py b/src/gcore/resources/cloud/inference/secrets.py new file mode 100644 index 00000000..6b168d22 --- /dev/null +++ b/src/gcore/resources/cloud/inference/secrets.py @@ -0,0 +1,628 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.inference import secret_list_params, secret_create_params, secret_replace_params +from ....types.cloud.inference.inference_secret import InferenceSecret + +__all__ = ["SecretsResource", "AsyncSecretsResource"] + + +class SecretsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SecretsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return SecretsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SecretsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return SecretsResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + data: secret_create_params.Data, + name: str, + type: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceSecret: + """ + Create inference secret + + Args: + project_id: Project ID + + data: Secret data. + + name: Secret name. + + type: Secret type. Currently only `aws-iam` is supported. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._post( + f"/cloud/v3/inference/{project_id}/secrets", + body=maybe_transform( + { + "data": data, + "name": name, + "type": type, + }, + secret_create_params.SecretCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceSecret, + ) + + def list( + self, + *, + project_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[InferenceSecret]: + """List inference secrets + + Args: + project_id: Project ID + + limit: Optional. + + Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._get_api_list( + f"/cloud/v3/inference/{project_id}/secrets", + page=SyncOffsetPage[InferenceSecret], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + secret_list_params.SecretListParams, + ), + ), + model=InferenceSecret, + ) + + def delete( + self, + secret_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete Inference Secret + + Args: + project_id: Project ID + + secret_name: Inference secret name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not secret_name: + raise ValueError(f"Expected a non-empty value for `secret_name` but received {secret_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v3/inference/{project_id}/secrets/{secret_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + secret_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceSecret: + """ + Get inference secret + + Args: + project_id: Project ID + + secret_name: Inference secret name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not secret_name: + raise ValueError(f"Expected a non-empty value for `secret_name` but received {secret_name!r}") + return self._get( + f"/cloud/v3/inference/{project_id}/secrets/{secret_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceSecret, + ) + + def replace( + self, + secret_name: str, + *, + project_id: int | None = None, + data: secret_replace_params.Data, + type: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceSecret: + """ + Replace inference secret + + Args: + project_id: Project ID + + secret_name: Inference secret name. + + data: Secret data. + + type: Secret type. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not secret_name: + raise ValueError(f"Expected a non-empty value for `secret_name` but received {secret_name!r}") + return self._put( + f"/cloud/v3/inference/{project_id}/secrets/{secret_name}", + body=maybe_transform( + { + "data": data, + "type": type, + }, + secret_replace_params.SecretReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceSecret, + ) + + +class AsyncSecretsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSecretsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncSecretsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSecretsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncSecretsResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + data: secret_create_params.Data, + name: str, + type: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceSecret: + """ + Create inference secret + + Args: + project_id: Project ID + + data: Secret data. + + name: Secret name. + + type: Secret type. Currently only `aws-iam` is supported. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return await self._post( + f"/cloud/v3/inference/{project_id}/secrets", + body=await async_maybe_transform( + { + "data": data, + "name": name, + "type": type, + }, + secret_create_params.SecretCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceSecret, + ) + + def list( + self, + *, + project_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[InferenceSecret, AsyncOffsetPage[InferenceSecret]]: + """List inference secrets + + Args: + project_id: Project ID + + limit: Optional. + + Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._get_api_list( + f"/cloud/v3/inference/{project_id}/secrets", + page=AsyncOffsetPage[InferenceSecret], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + secret_list_params.SecretListParams, + ), + ), + model=InferenceSecret, + ) + + async def delete( + self, + secret_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete Inference Secret + + Args: + project_id: Project ID + + secret_name: Inference secret name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not secret_name: + raise ValueError(f"Expected a non-empty value for `secret_name` but received {secret_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v3/inference/{project_id}/secrets/{secret_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + secret_name: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceSecret: + """ + Get inference secret + + Args: + project_id: Project ID + + secret_name: Inference secret name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not secret_name: + raise ValueError(f"Expected a non-empty value for `secret_name` but received {secret_name!r}") + return await self._get( + f"/cloud/v3/inference/{project_id}/secrets/{secret_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceSecret, + ) + + async def replace( + self, + secret_name: str, + *, + project_id: int | None = None, + data: secret_replace_params.Data, + type: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InferenceSecret: + """ + Replace inference secret + + Args: + project_id: Project ID + + secret_name: Inference secret name. + + data: Secret data. + + type: Secret type. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not secret_name: + raise ValueError(f"Expected a non-empty value for `secret_name` but received {secret_name!r}") + return await self._put( + f"/cloud/v3/inference/{project_id}/secrets/{secret_name}", + body=await async_maybe_transform( + { + "data": data, + "type": type, + }, + secret_replace_params.SecretReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InferenceSecret, + ) + + +class SecretsResourceWithRawResponse: + def __init__(self, secrets: SecretsResource) -> None: + self._secrets = secrets + + self.create = to_raw_response_wrapper( + secrets.create, + ) + self.list = to_raw_response_wrapper( + secrets.list, + ) + self.delete = to_raw_response_wrapper( + secrets.delete, + ) + self.get = to_raw_response_wrapper( + secrets.get, + ) + self.replace = to_raw_response_wrapper( + secrets.replace, + ) + + +class AsyncSecretsResourceWithRawResponse: + def __init__(self, secrets: AsyncSecretsResource) -> None: + self._secrets = secrets + + self.create = async_to_raw_response_wrapper( + secrets.create, + ) + self.list = async_to_raw_response_wrapper( + secrets.list, + ) + self.delete = async_to_raw_response_wrapper( + secrets.delete, + ) + self.get = async_to_raw_response_wrapper( + secrets.get, + ) + self.replace = async_to_raw_response_wrapper( + secrets.replace, + ) + + +class SecretsResourceWithStreamingResponse: + def __init__(self, secrets: SecretsResource) -> None: + self._secrets = secrets + + self.create = to_streamed_response_wrapper( + secrets.create, + ) + self.list = to_streamed_response_wrapper( + secrets.list, + ) + self.delete = to_streamed_response_wrapper( + secrets.delete, + ) + self.get = to_streamed_response_wrapper( + secrets.get, + ) + self.replace = to_streamed_response_wrapper( + secrets.replace, + ) + + +class AsyncSecretsResourceWithStreamingResponse: + def __init__(self, secrets: AsyncSecretsResource) -> None: + self._secrets = secrets + + self.create = async_to_streamed_response_wrapper( + secrets.create, + ) + self.list = async_to_streamed_response_wrapper( + secrets.list, + ) + self.delete = async_to_streamed_response_wrapper( + secrets.delete, + ) + self.get = async_to_streamed_response_wrapper( + secrets.get, + ) + self.replace = async_to_streamed_response_wrapper( + secrets.replace, + ) diff --git a/src/gcore/resources/cloud/instances/__init__.py b/src/gcore/resources/cloud/instances/__init__.py new file mode 100644 index 00000000..0f7240dd --- /dev/null +++ b/src/gcore/resources/cloud/instances/__init__.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .images import ( + ImagesResource, + AsyncImagesResource, + ImagesResourceWithRawResponse, + AsyncImagesResourceWithRawResponse, + ImagesResourceWithStreamingResponse, + AsyncImagesResourceWithStreamingResponse, +) +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from .metrics import ( + MetricsResource, + AsyncMetricsResource, + MetricsResourceWithRawResponse, + AsyncMetricsResourceWithRawResponse, + MetricsResourceWithStreamingResponse, + AsyncMetricsResourceWithStreamingResponse, +) +from .instances import ( + InstancesResource, + AsyncInstancesResource, + InstancesResourceWithRawResponse, + AsyncInstancesResourceWithRawResponse, + InstancesResourceWithStreamingResponse, + AsyncInstancesResourceWithStreamingResponse, +) +from .interfaces import ( + InterfacesResource, + AsyncInterfacesResource, + InterfacesResourceWithRawResponse, + AsyncInterfacesResourceWithRawResponse, + InterfacesResourceWithStreamingResponse, + AsyncInterfacesResourceWithStreamingResponse, +) + +__all__ = [ + "FlavorsResource", + "AsyncFlavorsResource", + "FlavorsResourceWithRawResponse", + "AsyncFlavorsResourceWithRawResponse", + "FlavorsResourceWithStreamingResponse", + "AsyncFlavorsResourceWithStreamingResponse", + "InterfacesResource", + "AsyncInterfacesResource", + "InterfacesResourceWithRawResponse", + "AsyncInterfacesResourceWithRawResponse", + "InterfacesResourceWithStreamingResponse", + "AsyncInterfacesResourceWithStreamingResponse", + "ImagesResource", + "AsyncImagesResource", + "ImagesResourceWithRawResponse", + "AsyncImagesResourceWithRawResponse", + "ImagesResourceWithStreamingResponse", + "AsyncImagesResourceWithStreamingResponse", + "MetricsResource", + "AsyncMetricsResource", + "MetricsResourceWithRawResponse", + "AsyncMetricsResourceWithRawResponse", + "MetricsResourceWithStreamingResponse", + "AsyncMetricsResourceWithStreamingResponse", + "InstancesResource", + "AsyncInstancesResource", + "InstancesResourceWithRawResponse", + "AsyncInstancesResourceWithRawResponse", + "InstancesResourceWithStreamingResponse", + "AsyncInstancesResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/instances/flavors.py b/src/gcore/resources/cloud/instances/flavors.py new file mode 100644 index 00000000..23ba0073 --- /dev/null +++ b/src/gcore/resources/cloud/instances/flavors.py @@ -0,0 +1,225 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.instances import flavor_list_params +from ....types.cloud.instances.instance_flavor_list import InstanceFlavorList + +__all__ = ["FlavorsResource", "AsyncFlavorsResource"] + + +class FlavorsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> FlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return FlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return FlavorsResourceWithStreamingResponse(self) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + disabled: bool | Omit = omit, + exclude_linux: bool | Omit = omit, + exclude_windows: bool | Omit = omit, + include_prices: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InstanceFlavorList: + """Retrieve a list of available instance flavors in the project and region. + + When + `include_prices` is specified, the list includes pricing information. Trial mode + clients see all prices as 0. Contact support for pricing errors. + + Args: + disabled: Flag for filtering disabled flavors in the region. Defaults to true + + exclude_linux: Set to true to exclude flavors dedicated to linux images. Default False + + exclude_windows: Set to true to exclude flavors dedicated to windows images. Default False + + include_prices: Set to true if the response should include flavor prices + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/flavors/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "disabled": disabled, + "exclude_linux": exclude_linux, + "exclude_windows": exclude_windows, + "include_prices": include_prices, + }, + flavor_list_params.FlavorListParams, + ), + ), + cast_to=InstanceFlavorList, + ) + + +class AsyncFlavorsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncFlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncFlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncFlavorsResourceWithStreamingResponse(self) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + disabled: bool | Omit = omit, + exclude_linux: bool | Omit = omit, + exclude_windows: bool | Omit = omit, + include_prices: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InstanceFlavorList: + """Retrieve a list of available instance flavors in the project and region. + + When + `include_prices` is specified, the list includes pricing information. Trial mode + clients see all prices as 0. Contact support for pricing errors. + + Args: + disabled: Flag for filtering disabled flavors in the region. Defaults to true + + exclude_linux: Set to true to exclude flavors dedicated to linux images. Default False + + exclude_windows: Set to true to exclude flavors dedicated to windows images. Default False + + include_prices: Set to true if the response should include flavor prices + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/flavors/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "disabled": disabled, + "exclude_linux": exclude_linux, + "exclude_windows": exclude_windows, + "include_prices": include_prices, + }, + flavor_list_params.FlavorListParams, + ), + ), + cast_to=InstanceFlavorList, + ) + + +class FlavorsResourceWithRawResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_raw_response_wrapper( + flavors.list, + ) + + +class AsyncFlavorsResourceWithRawResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_raw_response_wrapper( + flavors.list, + ) + + +class FlavorsResourceWithStreamingResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_streamed_response_wrapper( + flavors.list, + ) + + +class AsyncFlavorsResourceWithStreamingResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_streamed_response_wrapper( + flavors.list, + ) diff --git a/src/gcore/resources/cloud/instances/images.py b/src/gcore/resources/cloud/instances/images.py new file mode 100644 index 00000000..23e3ba1c --- /dev/null +++ b/src/gcore/resources/cloud/instances/images.py @@ -0,0 +1,1003 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.image import Image +from ....types.cloud.instances import ( + image_get_params, + image_list_params, + image_update_params, + image_upload_params, + image_create_from_volume_params, +) +from ....types.cloud.image_list import ImageList +from ....types.cloud.task_id_list import TaskIDList +from ....types.cloud.tag_update_map_param import TagUpdateMapParam + +__all__ = ["ImagesResource", "AsyncImagesResource"] + + +class ImagesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ImagesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ImagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ImagesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ImagesResourceWithStreamingResponse(self) + + def update( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + hw_firmware_type: Literal["bios", "uefi"] | Omit = omit, + hw_machine_type: Literal["pc", "q35"] | Omit = omit, + is_baremetal: bool | Omit = omit, + name: str | Omit = omit, + os_type: Literal["linux", "windows"] | Omit = omit, + ssh_key: Literal["allow", "deny", "required"] | Omit = omit, + tags: TagUpdateMapParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Image: + """ + Update image properties and tags. + + Args: + hw_firmware_type: Specifies the type of firmware with which to boot the guest. + + hw_machine_type: A virtual chipset type. + + is_baremetal: Set to true if the image will be used by bare metal servers. + + name: Image display name + + os_type: The operating system installed on the image. + + ssh_key: Whether the image supports SSH key or not + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return self._patch( + f"/cloud/v1/images/{project_id}/{region_id}/{image_id}", + body=maybe_transform( + { + "hw_firmware_type": hw_firmware_type, + "hw_machine_type": hw_machine_type, + "is_baremetal": is_baremetal, + "name": name, + "os_type": os_type, + "ssh_key": ssh_key, + "tags": tags, + }, + image_update_params.ImageUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Image, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + include_prices: bool | Omit = omit, + private: str | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + visibility: Literal["private", "public", "shared"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ImageList: + """Retrieve a list of available images in the project and region. + + The list can be + filtered by visibility, tags, and other parameters. Returned entities are owned + by the project or are public/shared with the client. + + Args: + include_prices: Show price + + private: Any value to show private images + + tag_key: Filter by tag keys. + + tag_key_value: Filter by tag key-value pairs. Must be a valid JSON string. + + visibility: Image visibility. Globally visible images are public + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/images/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "include_prices": include_prices, + "private": private, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + "visibility": visibility, + }, + image_list_params.ImageListParams, + ), + ), + cast_to=ImageList, + ) + + def delete( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Delete a specific image. + + The image cannot be deleted if it is used by protected + snapshots. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return self._delete( + f"/cloud/v1/images/{project_id}/{region_id}/{image_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def create_from_volume( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + volume_id: str, + architecture: Literal["aarch64", "x86_64"] | Omit = omit, + hw_firmware_type: Optional[Literal["bios", "uefi"]] | Omit = omit, + hw_machine_type: Optional[Literal["pc", "q35"]] | Omit = omit, + is_baremetal: bool | Omit = omit, + os_type: Literal["linux", "windows"] | Omit = omit, + source: Literal["volume"] | Omit = omit, + ssh_key: Literal["allow", "deny", "required"] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Create a new image from a bootable volume. + + The volume must be bootable to create + an image from it. + + Args: + name: Image name + + volume_id: Required if source is volume. Volume id + + architecture: Image CPU architecture type: `aarch64`, `x86_64` + + hw_firmware_type: Specifies the type of firmware with which to boot the guest. + + hw_machine_type: A virtual chipset type. + + is_baremetal: Set to true if the image will be used by bare metal servers. Defaults to false. + + os_type: The operating system installed on the image. + + source: Image source + + ssh_key: Whether the image supports SSH key or not + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/images/{project_id}/{region_id}", + body=maybe_transform( + { + "name": name, + "volume_id": volume_id, + "architecture": architecture, + "hw_firmware_type": hw_firmware_type, + "hw_machine_type": hw_machine_type, + "is_baremetal": is_baremetal, + "os_type": os_type, + "source": source, + "ssh_key": ssh_key, + "tags": tags, + }, + image_create_from_volume_params.ImageCreateFromVolumeParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + include_prices: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Image: + """ + Retrieve detailed information about a specific image. + + Args: + include_prices: Show price + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return self._get( + f"/cloud/v1/images/{project_id}/{region_id}/{image_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"include_prices": include_prices}, image_get_params.ImageGetParams), + ), + cast_to=Image, + ) + + def upload( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + url: str, + architecture: Literal["aarch64", "x86_64"] | Omit = omit, + cow_format: bool | Omit = omit, + hw_firmware_type: Optional[Literal["bios", "uefi"]] | Omit = omit, + hw_machine_type: Optional[Literal["pc", "q35"]] | Omit = omit, + is_baremetal: bool | Omit = omit, + os_distro: Optional[str] | Omit = omit, + os_type: Literal["linux", "windows"] | Omit = omit, + os_version: Optional[str] | Omit = omit, + ssh_key: Literal["allow", "deny", "required"] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Upload an image from a URL. + + The image can be configured with various properties + like OS type, architecture, and tags. + + Args: + name: Image name + + url: URL + + architecture: Image CPU architecture type: `aarch64`, `x86_64` + + cow_format: When True, image cannot be deleted unless all volumes, created from it, are + deleted. + + hw_firmware_type: Specifies the type of firmware with which to boot the guest. + + hw_machine_type: A virtual chipset type. + + is_baremetal: Set to true if the image will be used by bare metal servers. Defaults to false. + + os_distro: OS Distribution, i.e. Debian, CentOS, Ubuntu, CoreOS etc. + + os_type: The operating system installed on the image. + + os_version: OS version, i.e. 22.04 (for Ubuntu) or 9.4 for Debian + + ssh_key: Whether the image supports SSH key or not + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/downloadimage/{project_id}/{region_id}", + body=maybe_transform( + { + "name": name, + "url": url, + "architecture": architecture, + "cow_format": cow_format, + "hw_firmware_type": hw_firmware_type, + "hw_machine_type": hw_machine_type, + "is_baremetal": is_baremetal, + "os_distro": os_distro, + "os_type": os_type, + "os_version": os_version, + "ssh_key": ssh_key, + "tags": tags, + }, + image_upload_params.ImageUploadParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncImagesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncImagesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncImagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncImagesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncImagesResourceWithStreamingResponse(self) + + async def update( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + hw_firmware_type: Literal["bios", "uefi"] | Omit = omit, + hw_machine_type: Literal["pc", "q35"] | Omit = omit, + is_baremetal: bool | Omit = omit, + name: str | Omit = omit, + os_type: Literal["linux", "windows"] | Omit = omit, + ssh_key: Literal["allow", "deny", "required"] | Omit = omit, + tags: TagUpdateMapParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Image: + """ + Update image properties and tags. + + Args: + hw_firmware_type: Specifies the type of firmware with which to boot the guest. + + hw_machine_type: A virtual chipset type. + + is_baremetal: Set to true if the image will be used by bare metal servers. + + name: Image display name + + os_type: The operating system installed on the image. + + ssh_key: Whether the image supports SSH key or not + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return await self._patch( + f"/cloud/v1/images/{project_id}/{region_id}/{image_id}", + body=await async_maybe_transform( + { + "hw_firmware_type": hw_firmware_type, + "hw_machine_type": hw_machine_type, + "is_baremetal": is_baremetal, + "name": name, + "os_type": os_type, + "ssh_key": ssh_key, + "tags": tags, + }, + image_update_params.ImageUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Image, + ) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + include_prices: bool | Omit = omit, + private: str | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + visibility: Literal["private", "public", "shared"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ImageList: + """Retrieve a list of available images in the project and region. + + The list can be + filtered by visibility, tags, and other parameters. Returned entities are owned + by the project or are public/shared with the client. + + Args: + include_prices: Show price + + private: Any value to show private images + + tag_key: Filter by tag keys. + + tag_key_value: Filter by tag key-value pairs. Must be a valid JSON string. + + visibility: Image visibility. Globally visible images are public + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/images/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "include_prices": include_prices, + "private": private, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + "visibility": visibility, + }, + image_list_params.ImageListParams, + ), + ), + cast_to=ImageList, + ) + + async def delete( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Delete a specific image. + + The image cannot be deleted if it is used by protected + snapshots. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return await self._delete( + f"/cloud/v1/images/{project_id}/{region_id}/{image_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def create_from_volume( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + volume_id: str, + architecture: Literal["aarch64", "x86_64"] | Omit = omit, + hw_firmware_type: Optional[Literal["bios", "uefi"]] | Omit = omit, + hw_machine_type: Optional[Literal["pc", "q35"]] | Omit = omit, + is_baremetal: bool | Omit = omit, + os_type: Literal["linux", "windows"] | Omit = omit, + source: Literal["volume"] | Omit = omit, + ssh_key: Literal["allow", "deny", "required"] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Create a new image from a bootable volume. + + The volume must be bootable to create + an image from it. + + Args: + name: Image name + + volume_id: Required if source is volume. Volume id + + architecture: Image CPU architecture type: `aarch64`, `x86_64` + + hw_firmware_type: Specifies the type of firmware with which to boot the guest. + + hw_machine_type: A virtual chipset type. + + is_baremetal: Set to true if the image will be used by bare metal servers. Defaults to false. + + os_type: The operating system installed on the image. + + source: Image source + + ssh_key: Whether the image supports SSH key or not + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/images/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "name": name, + "volume_id": volume_id, + "architecture": architecture, + "hw_firmware_type": hw_firmware_type, + "hw_machine_type": hw_machine_type, + "is_baremetal": is_baremetal, + "os_type": os_type, + "source": source, + "ssh_key": ssh_key, + "tags": tags, + }, + image_create_from_volume_params.ImageCreateFromVolumeParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + image_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + include_prices: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Image: + """ + Retrieve detailed information about a specific image. + + Args: + include_prices: Show price + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not image_id: + raise ValueError(f"Expected a non-empty value for `image_id` but received {image_id!r}") + return await self._get( + f"/cloud/v1/images/{project_id}/{region_id}/{image_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"include_prices": include_prices}, image_get_params.ImageGetParams), + ), + cast_to=Image, + ) + + async def upload( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + url: str, + architecture: Literal["aarch64", "x86_64"] | Omit = omit, + cow_format: bool | Omit = omit, + hw_firmware_type: Optional[Literal["bios", "uefi"]] | Omit = omit, + hw_machine_type: Optional[Literal["pc", "q35"]] | Omit = omit, + is_baremetal: bool | Omit = omit, + os_distro: Optional[str] | Omit = omit, + os_type: Literal["linux", "windows"] | Omit = omit, + os_version: Optional[str] | Omit = omit, + ssh_key: Literal["allow", "deny", "required"] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Upload an image from a URL. + + The image can be configured with various properties + like OS type, architecture, and tags. + + Args: + name: Image name + + url: URL + + architecture: Image CPU architecture type: `aarch64`, `x86_64` + + cow_format: When True, image cannot be deleted unless all volumes, created from it, are + deleted. + + hw_firmware_type: Specifies the type of firmware with which to boot the guest. + + hw_machine_type: A virtual chipset type. + + is_baremetal: Set to true if the image will be used by bare metal servers. Defaults to false. + + os_distro: OS Distribution, i.e. Debian, CentOS, Ubuntu, CoreOS etc. + + os_type: The operating system installed on the image. + + os_version: OS version, i.e. 22.04 (for Ubuntu) or 9.4 for Debian + + ssh_key: Whether the image supports SSH key or not + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/downloadimage/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "name": name, + "url": url, + "architecture": architecture, + "cow_format": cow_format, + "hw_firmware_type": hw_firmware_type, + "hw_machine_type": hw_machine_type, + "is_baremetal": is_baremetal, + "os_distro": os_distro, + "os_type": os_type, + "os_version": os_version, + "ssh_key": ssh_key, + "tags": tags, + }, + image_upload_params.ImageUploadParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class ImagesResourceWithRawResponse: + def __init__(self, images: ImagesResource) -> None: + self._images = images + + self.update = to_raw_response_wrapper( + images.update, + ) + self.list = to_raw_response_wrapper( + images.list, + ) + self.delete = to_raw_response_wrapper( + images.delete, + ) + self.create_from_volume = to_raw_response_wrapper( + images.create_from_volume, + ) + self.get = to_raw_response_wrapper( + images.get, + ) + self.upload = to_raw_response_wrapper( + images.upload, + ) + + +class AsyncImagesResourceWithRawResponse: + def __init__(self, images: AsyncImagesResource) -> None: + self._images = images + + self.update = async_to_raw_response_wrapper( + images.update, + ) + self.list = async_to_raw_response_wrapper( + images.list, + ) + self.delete = async_to_raw_response_wrapper( + images.delete, + ) + self.create_from_volume = async_to_raw_response_wrapper( + images.create_from_volume, + ) + self.get = async_to_raw_response_wrapper( + images.get, + ) + self.upload = async_to_raw_response_wrapper( + images.upload, + ) + + +class ImagesResourceWithStreamingResponse: + def __init__(self, images: ImagesResource) -> None: + self._images = images + + self.update = to_streamed_response_wrapper( + images.update, + ) + self.list = to_streamed_response_wrapper( + images.list, + ) + self.delete = to_streamed_response_wrapper( + images.delete, + ) + self.create_from_volume = to_streamed_response_wrapper( + images.create_from_volume, + ) + self.get = to_streamed_response_wrapper( + images.get, + ) + self.upload = to_streamed_response_wrapper( + images.upload, + ) + + +class AsyncImagesResourceWithStreamingResponse: + def __init__(self, images: AsyncImagesResource) -> None: + self._images = images + + self.update = async_to_streamed_response_wrapper( + images.update, + ) + self.list = async_to_streamed_response_wrapper( + images.list, + ) + self.delete = async_to_streamed_response_wrapper( + images.delete, + ) + self.create_from_volume = async_to_streamed_response_wrapper( + images.create_from_volume, + ) + self.get = async_to_streamed_response_wrapper( + images.get, + ) + self.upload = async_to_streamed_response_wrapper( + images.upload, + ) diff --git a/src/gcore/resources/cloud/instances/instances.py b/src/gcore/resources/cloud/instances/instances.py new file mode 100644 index 00000000..c2e445aa --- /dev/null +++ b/src/gcore/resources/cloud/instances/instances.py @@ -0,0 +1,2437 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from datetime import datetime +from typing_extensions import Literal, overload + +import httpx + +from .images import ( + ImagesResource, + AsyncImagesResource, + ImagesResourceWithRawResponse, + AsyncImagesResourceWithRawResponse, + ImagesResourceWithStreamingResponse, + AsyncImagesResourceWithStreamingResponse, +) +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from .metrics import ( + MetricsResource, + AsyncMetricsResource, + MetricsResourceWithRawResponse, + AsyncMetricsResourceWithRawResponse, + MetricsResourceWithStreamingResponse, + AsyncMetricsResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import required_args, maybe_transform, async_maybe_transform +from ...._compat import cached_property +from .interfaces import ( + InterfacesResource, + AsyncInterfacesResource, + InterfacesResourceWithRawResponse, + AsyncInterfacesResourceWithRawResponse, + InterfacesResourceWithStreamingResponse, + AsyncInterfacesResourceWithStreamingResponse, +) +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ....types.cloud import ( + instance_list_params, + instance_action_params, + instance_create_params, + instance_delete_params, + instance_resize_params, + instance_update_params, + instance_get_console_params, + instance_assign_security_group_params, + instance_add_to_placement_group_params, + instance_unassign_security_group_params, +) +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.console import Console +from ....types.cloud.instance import Instance +from ....types.cloud.task_id_list import TaskIDList +from ....types.cloud.instance_interface import InstanceInterface +from ....types.cloud.tag_update_map_param import TagUpdateMapParam + +__all__ = ["InstancesResource", "AsyncInstancesResource"] + + +class InstancesResource(SyncAPIResource): + @cached_property + def flavors(self) -> FlavorsResource: + return FlavorsResource(self._client) + + @cached_property + def interfaces(self) -> InterfacesResource: + return InterfacesResource(self._client) + + @cached_property + def images(self) -> ImagesResource: + return ImagesResource(self._client) + + @cached_property + def metrics(self) -> MetricsResource: + return MetricsResource(self._client) + + @cached_property + def with_raw_response(self) -> InstancesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return InstancesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InstancesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return InstancesResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor: str, + interfaces: Iterable[instance_create_params.Interface], + volumes: Iterable[instance_create_params.Volume], + allow_app_ports: bool | Omit = omit, + configuration: Optional[Dict[str, object]] | Omit = omit, + name: str | Omit = omit, + name_template: str | Omit = omit, + password: str | Omit = omit, + security_groups: Iterable[instance_create_params.SecurityGroup] | Omit = omit, + servergroup_id: str | Omit = omit, + ssh_key_name: Optional[str] | Omit = omit, + tags: object | Omit = omit, + user_data: str | Omit = omit, + username: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create an instance with specified configuration. + + How to get access: + + For Linux, + + - Use the `user_data` field to provide a + [cloud-init script](https://cloudinit.readthedocs.io/en/latest/reference/examples.html) + in base64 to apply configurations to the instance. + - Specify the `username` and `password` to create a new user. + - When only `password` is provided, it is set as the password for the default + user of the image. + - The `user_data` is ignored when the `password` is specified. + + For Windows, + + - Use the `user_data` field to provide a + [cloudbase-init script](https://cloudbase-init.readthedocs.io/en/latest/userdata.html#cloud-config) + in base64 to create new users on Windows. + - Use the `password` field to set the password for the 'Admin' user on Windows. + - The password of the Admin user cannot be updated via `user_data`. + - The `username` cannot be specified in the request. + + Args: + project_id: Project ID + + region_id: Region ID + + flavor: The flavor of the instance. + + interfaces: A list of network interfaces for the instance. You can create one or more + interfaces - private, public, or both. + + volumes: List of volumes that will be attached to the instance. + + allow_app_ports: Set to `true` if creating the instance from an `apptemplate`. This allows + application ports in the security group for instances created from a marketplace + application template. + + configuration: Parameters for the application template if creating the instance from an + `apptemplate`. + + name: Instance name. + + name_template: If you want the instance name to be automatically generated based on IP + addresses, you can provide a name template instead of specifying the name + manually. The template should include a placeholder that will be replaced during + provisioning. Supported placeholders are: `{ip_octets}` (last 3 octets of the + IP), `{two_ip_octets}`, and `{one_ip_octet}`. + + password: For Linux instances, 'username' and 'password' are used to create a new user. + When only 'password' is provided, it is set as the password for the default user + of the image. For Windows instances, 'username' cannot be specified. Use the + 'password' field to set the password for the 'Admin' user on Windows. Use the + 'user_data' field to provide a script to create new users on Windows. The + password of the Admin user cannot be updated via 'user_data'. + + security_groups: Specifies security group UUIDs to be applied to all instance network interfaces. + + servergroup_id: Placement group ID for instance placement policy. + + Supported group types: + + - `anti-affinity`: Ensures instances are placed on different hosts for high + availability. + - `affinity`: Places instances on the same host for low-latency communication. + - `soft-anti-affinity`: Tries to place instances on different hosts but allows + sharing if needed. + + ssh_key_name: Specifies the name of the SSH keypair, created via the + [/v1/`ssh_keys` endpoint](/docs/api-reference/cloud/ssh-keys/add-or-generate-ssh-key). + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + user_data: String in base64 format. For Linux instances, 'user_data' is ignored when + 'password' field is provided. For Windows instances, Admin user password is set + by 'password' field and cannot be updated via 'user_data'. Examples of the + `user_data`: https://cloudinit.readthedocs.io/en/latest/topics/examples.html + + username: For Linux instances, 'username' and 'password' are used to create a new user. + For Windows instances, 'username' cannot be specified. Use 'password' field to + set the password for the 'Admin' user on Windows. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v2/instances/{project_id}/{region_id}", + body=maybe_transform( + { + "flavor": flavor, + "interfaces": interfaces, + "volumes": volumes, + "allow_app_ports": allow_app_ports, + "configuration": configuration, + "name": name, + "name_template": name_template, + "password": password, + "security_groups": security_groups, + "servergroup_id": servergroup_id, + "ssh_key_name": ssh_key_name, + "tags": tags, + "user_data": user_data, + "username": username, + }, + instance_create_params.InstanceCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Instance: + """ + Rename instance or update tags + + Args: + project_id: Project ID + + region_id: Region ID + + instance_id: Instance ID + + name: Name + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._patch( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}", + body=maybe_transform( + { + "name": name, + "tags": tags, + }, + instance_update_params.InstanceUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Instance, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + available_floating: bool | Omit = omit, + changes_before: Union[str, datetime] | Omit = omit, + changes_since: Union[str, datetime] | Omit = omit, + exclude_flavor_prefix: str | Omit = omit, + exclude_secgroup: str | Omit = omit, + flavor_id: str | Omit = omit, + flavor_prefix: str | Omit = omit, + include_ai: bool | Omit = omit, + include_baremetal: bool | Omit = omit, + include_k8s: bool | Omit = omit, + ip: str | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + only_isolated: bool | Omit = omit, + only_with_fixed_external_ip: bool | Omit = omit, + order_by: Literal["created.asc", "created.desc", "name.asc", "name.desc", "status.asc", "status.desc"] + | Omit = omit, + profile_name: str | Omit = omit, + protection_status: Literal["Active", "Queued", "Error"] | Omit = omit, + status: Literal[ + "ACTIVE", + "BUILD", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PAUSED", + "REBOOT", + "REBUILD", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "VERIFY_RESIZE", + ] + | Omit = omit, + tag_key_value: str | Omit = omit, + tag_value: SequenceNotStr[str] | Omit = omit, + type_ddos_profile: Literal["basic", "advanced"] | Omit = omit, + uuid: str | Omit = omit, + with_ddos: bool | Omit = omit, + with_interfaces_name: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[Instance]: + """List all instances in the specified project and region. + + Results can be filtered + by various parameters like name, status, and IP address. + + Args: + project_id: Project ID + + region_id: Region ID + + available_floating: Only show instances which are able to handle floating address + + changes_before: Filters the instances by a date and time stamp when the instances last changed. + + changes_since: Filters the instances by a date and time stamp when the instances last changed + status. + + exclude_flavor_prefix: Exclude instances with specified flavor prefix + + exclude_secgroup: Exclude instances with specified security group name + + flavor_id: Filter out instances by `flavor_id`. Flavor id must match exactly. + + flavor_prefix: Filter out instances by `flavor_prefix`. + + include_ai: Include GPU clusters' servers + + include_baremetal: Include bare metal servers. Please, use `GET /v1/bminstances/` instead + + include_k8s: Include managed k8s worker nodes + + ip: An IPv4 address to filter results by. Note: partial matches are allowed. For + example, searching for 192.168.0.1 will return 192.168.0.1, 192.168.0.10, + 192.168.0.110, and so on. + + limit: Optional. Limit the number of returned items + + name: Filter instances by name. You can provide a full or partial name, instances with + matching names will be returned. For example, entering 'test' will return all + instances that contain 'test' in their name. + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + only_isolated: Include only isolated instances + + only_with_fixed_external_ip: Return bare metals only with external fixed IP addresses. + + order_by: Order by field and direction. + + profile_name: Filter result by ddos protection profile name. Effective only with `with_ddos` + set to true. + + protection_status: Filter result by DDoS `protection_status`. if parameter is provided. Effective + only with `with_ddos` set to true. (Active, Queued or Error) + + status: Filters instances by status. + + tag_key_value: Optional. Filter by tag key-value pairs. + + tag_value: Optional. Filter by tag values. ?`tag_value`=value1&`tag_value`=value2 + + type_ddos_profile: Return bare metals either only with advanced or only basic DDoS protection. + Effective only with `with_ddos` set to true. (advanced or basic) + + uuid: Filter the server list result by the UUID of the server. Allowed UUID part + + with_ddos: Include DDoS profile information in the response when set to `true`. Otherwise, + the `ddos_profile` field in the response is `null` by default. + + with_interfaces_name: Include `interface_name` in the addresses + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/instances/{project_id}/{region_id}", + page=SyncOffsetPage[Instance], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "available_floating": available_floating, + "changes_before": changes_before, + "changes_since": changes_since, + "exclude_flavor_prefix": exclude_flavor_prefix, + "exclude_secgroup": exclude_secgroup, + "flavor_id": flavor_id, + "flavor_prefix": flavor_prefix, + "include_ai": include_ai, + "include_baremetal": include_baremetal, + "include_k8s": include_k8s, + "ip": ip, + "limit": limit, + "name": name, + "offset": offset, + "only_isolated": only_isolated, + "only_with_fixed_external_ip": only_with_fixed_external_ip, + "order_by": order_by, + "profile_name": profile_name, + "protection_status": protection_status, + "status": status, + "tag_key_value": tag_key_value, + "tag_value": tag_value, + "type_ddos_profile": type_ddos_profile, + "uuid": uuid, + "with_ddos": with_ddos, + "with_interfaces_name": with_interfaces_name, + }, + instance_list_params.InstanceListParams, + ), + ), + model=Instance, + ) + + def delete( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + delete_floatings: bool | Omit = omit, + floatings: str | Omit = omit, + reserved_fixed_ips: str | Omit = omit, + volumes: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete instance + + Args: + project_id: Project ID + + region_id: Region ID + + instance_id: Instance ID + + delete_floatings: True if it is required to delete floating IPs assigned to the instance. Can't be + used with `floatings`. + + floatings: Comma separated list of floating ids that should be deleted. Can't be used with + `delete_floatings`. + + reserved_fixed_ips: Comma separated list of port IDs to be deleted with the instance + + volumes: Comma separated list of volume IDs to be deleted with the instance + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._delete( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "delete_floatings": delete_floatings, + "floatings": floatings, + "reserved_fixed_ips": reserved_fixed_ips, + "volumes": volumes, + }, + instance_delete_params.InstanceDeleteParams, + ), + ), + cast_to=TaskIDList, + ) + + @overload + def action( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["start"], + activate_profile: Optional[bool] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + The action can be one of: start, stop, reboot, powercycle, suspend or resume. + Suspend and resume are not available for bare metal instances. + + Args: + action: Instance action name + + activate_profile: Used on start instance to activate Advanced DDoS profile + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def action( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["reboot", "reboot_hard", "resume", "stop", "suspend"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + The action can be one of: start, stop, reboot, powercycle, suspend or resume. + Suspend and resume are not available for bare metal instances. + + Args: + action: Instance action name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["action"]) + def action( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["start"] | Literal["reboot", "reboot_hard", "resume", "stop", "suspend"], + activate_profile: Optional[bool] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._post( + f"/cloud/v2/instances/{project_id}/{region_id}/{instance_id}/action", + body=maybe_transform( + { + "action": action, + "activate_profile": activate_profile, + }, + instance_action_params.InstanceActionParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def add_to_placement_group( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + servergroup_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Add an instance to a server group. + + The instance must not already be in a server + group. Bare metal servers do not support server groups. + + Args: + servergroup_id: Anti-affinity or affinity or soft-anti-affinity server group ID. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/put_into_servergroup", + body=maybe_transform( + {"servergroup_id": servergroup_id}, + instance_add_to_placement_group_params.InstanceAddToPlacementGroupParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def assign_security_group( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + ports_security_group_names: Iterable[instance_assign_security_group_params.PortsSecurityGroupName] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Assign the security group to the server. + + To assign multiple security groups to + all ports, use the NULL value for the `port_id` field + + Args: + name: Security group name, applies to all ports + + ports_security_group_names: Port security groups mapping + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/addsecuritygroup", + body=maybe_transform( + { + "name": name, + "ports_security_group_names": ports_security_group_names, + }, + instance_assign_security_group_params.InstanceAssignSecurityGroupParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def disable_port_security( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InstanceInterface: + """ + Disable port security for instance interface + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return self._post( + f"/cloud/v1/ports/{project_id}/{region_id}/{port_id}/disable_port_security", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InstanceInterface, + ) + + def enable_port_security( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InstanceInterface: + """ + Enable port security for instance interface + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return self._post( + f"/cloud/v1/ports/{project_id}/{region_id}/{port_id}/enable_port_security", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InstanceInterface, + ) + + def get( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Instance: + """Retrieve detailed information about a specific instance. + + The response content + language for `ddos_profile` can be controlled via the 'language' cookie + parameter. + + **Cookie Parameters**: + + - `language` (str, optional): Language for the response content. Affects the + `ddos_profile` field. Supported values: + - `'en'` (default) + - `'de'` + - `'ru'` + + Args: + project_id: Project ID + + region_id: Region ID + + instance_id: Instance ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._get( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Instance, + ) + + def get_console( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + console_type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Console: + """ + Get instance console URL + + Args: + console_type: Console type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._get( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/get_console", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + {"console_type": console_type}, instance_get_console_params.InstanceGetConsoleParams + ), + ), + cast_to=Console, + ) + + def remove_from_placement_group( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Remove an instance from its current server group. + + The instance must be in a + server group to be removed. Bare metal servers do not support server groups. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/remove_from_servergroup", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def resize( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Change flavor of the instance + + Args: + flavor_id: Flavor ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/changeflavor", + body=maybe_transform({"flavor_id": flavor_id}, instance_resize_params.InstanceResizeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def unassign_security_group( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + ports_security_group_names: Iterable[instance_unassign_security_group_params.PortsSecurityGroupName] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Un-assign the security group to the server. + + To un-assign multiple security + groups to all ports, use the NULL value for the `port_id` field + + Args: + name: Security group name, applies to all ports + + ports_security_group_names: Port security groups mapping + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/delsecuritygroup", + body=maybe_transform( + { + "name": name, + "ports_security_group_names": ports_security_group_names, + }, + instance_unassign_security_group_params.InstanceUnassignSecurityGroupParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncInstancesResource(AsyncAPIResource): + @cached_property + def flavors(self) -> AsyncFlavorsResource: + return AsyncFlavorsResource(self._client) + + @cached_property + def interfaces(self) -> AsyncInterfacesResource: + return AsyncInterfacesResource(self._client) + + @cached_property + def images(self) -> AsyncImagesResource: + return AsyncImagesResource(self._client) + + @cached_property + def metrics(self) -> AsyncMetricsResource: + return AsyncMetricsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncInstancesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncInstancesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInstancesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncInstancesResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor: str, + interfaces: Iterable[instance_create_params.Interface], + volumes: Iterable[instance_create_params.Volume], + allow_app_ports: bool | Omit = omit, + configuration: Optional[Dict[str, object]] | Omit = omit, + name: str | Omit = omit, + name_template: str | Omit = omit, + password: str | Omit = omit, + security_groups: Iterable[instance_create_params.SecurityGroup] | Omit = omit, + servergroup_id: str | Omit = omit, + ssh_key_name: Optional[str] | Omit = omit, + tags: object | Omit = omit, + user_data: str | Omit = omit, + username: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create an instance with specified configuration. + + How to get access: + + For Linux, + + - Use the `user_data` field to provide a + [cloud-init script](https://cloudinit.readthedocs.io/en/latest/reference/examples.html) + in base64 to apply configurations to the instance. + - Specify the `username` and `password` to create a new user. + - When only `password` is provided, it is set as the password for the default + user of the image. + - The `user_data` is ignored when the `password` is specified. + + For Windows, + + - Use the `user_data` field to provide a + [cloudbase-init script](https://cloudbase-init.readthedocs.io/en/latest/userdata.html#cloud-config) + in base64 to create new users on Windows. + - Use the `password` field to set the password for the 'Admin' user on Windows. + - The password of the Admin user cannot be updated via `user_data`. + - The `username` cannot be specified in the request. + + Args: + project_id: Project ID + + region_id: Region ID + + flavor: The flavor of the instance. + + interfaces: A list of network interfaces for the instance. You can create one or more + interfaces - private, public, or both. + + volumes: List of volumes that will be attached to the instance. + + allow_app_ports: Set to `true` if creating the instance from an `apptemplate`. This allows + application ports in the security group for instances created from a marketplace + application template. + + configuration: Parameters for the application template if creating the instance from an + `apptemplate`. + + name: Instance name. + + name_template: If you want the instance name to be automatically generated based on IP + addresses, you can provide a name template instead of specifying the name + manually. The template should include a placeholder that will be replaced during + provisioning. Supported placeholders are: `{ip_octets}` (last 3 octets of the + IP), `{two_ip_octets}`, and `{one_ip_octet}`. + + password: For Linux instances, 'username' and 'password' are used to create a new user. + When only 'password' is provided, it is set as the password for the default user + of the image. For Windows instances, 'username' cannot be specified. Use the + 'password' field to set the password for the 'Admin' user on Windows. Use the + 'user_data' field to provide a script to create new users on Windows. The + password of the Admin user cannot be updated via 'user_data'. + + security_groups: Specifies security group UUIDs to be applied to all instance network interfaces. + + servergroup_id: Placement group ID for instance placement policy. + + Supported group types: + + - `anti-affinity`: Ensures instances are placed on different hosts for high + availability. + - `affinity`: Places instances on the same host for low-latency communication. + - `soft-anti-affinity`: Tries to place instances on different hosts but allows + sharing if needed. + + ssh_key_name: Specifies the name of the SSH keypair, created via the + [/v1/`ssh_keys` endpoint](/docs/api-reference/cloud/ssh-keys/add-or-generate-ssh-key). + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + user_data: String in base64 format. For Linux instances, 'user_data' is ignored when + 'password' field is provided. For Windows instances, Admin user password is set + by 'password' field and cannot be updated via 'user_data'. Examples of the + `user_data`: https://cloudinit.readthedocs.io/en/latest/topics/examples.html + + username: For Linux instances, 'username' and 'password' are used to create a new user. + For Windows instances, 'username' cannot be specified. Use 'password' field to + set the password for the 'Admin' user on Windows. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v2/instances/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "flavor": flavor, + "interfaces": interfaces, + "volumes": volumes, + "allow_app_ports": allow_app_ports, + "configuration": configuration, + "name": name, + "name_template": name_template, + "password": password, + "security_groups": security_groups, + "servergroup_id": servergroup_id, + "ssh_key_name": ssh_key_name, + "tags": tags, + "user_data": user_data, + "username": username, + }, + instance_create_params.InstanceCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Instance: + """ + Rename instance or update tags + + Args: + project_id: Project ID + + region_id: Region ID + + instance_id: Instance ID + + name: Name + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._patch( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}", + body=await async_maybe_transform( + { + "name": name, + "tags": tags, + }, + instance_update_params.InstanceUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Instance, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + available_floating: bool | Omit = omit, + changes_before: Union[str, datetime] | Omit = omit, + changes_since: Union[str, datetime] | Omit = omit, + exclude_flavor_prefix: str | Omit = omit, + exclude_secgroup: str | Omit = omit, + flavor_id: str | Omit = omit, + flavor_prefix: str | Omit = omit, + include_ai: bool | Omit = omit, + include_baremetal: bool | Omit = omit, + include_k8s: bool | Omit = omit, + ip: str | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + only_isolated: bool | Omit = omit, + only_with_fixed_external_ip: bool | Omit = omit, + order_by: Literal["created.asc", "created.desc", "name.asc", "name.desc", "status.asc", "status.desc"] + | Omit = omit, + profile_name: str | Omit = omit, + protection_status: Literal["Active", "Queued", "Error"] | Omit = omit, + status: Literal[ + "ACTIVE", + "BUILD", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PAUSED", + "REBOOT", + "REBUILD", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "VERIFY_RESIZE", + ] + | Omit = omit, + tag_key_value: str | Omit = omit, + tag_value: SequenceNotStr[str] | Omit = omit, + type_ddos_profile: Literal["basic", "advanced"] | Omit = omit, + uuid: str | Omit = omit, + with_ddos: bool | Omit = omit, + with_interfaces_name: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Instance, AsyncOffsetPage[Instance]]: + """List all instances in the specified project and region. + + Results can be filtered + by various parameters like name, status, and IP address. + + Args: + project_id: Project ID + + region_id: Region ID + + available_floating: Only show instances which are able to handle floating address + + changes_before: Filters the instances by a date and time stamp when the instances last changed. + + changes_since: Filters the instances by a date and time stamp when the instances last changed + status. + + exclude_flavor_prefix: Exclude instances with specified flavor prefix + + exclude_secgroup: Exclude instances with specified security group name + + flavor_id: Filter out instances by `flavor_id`. Flavor id must match exactly. + + flavor_prefix: Filter out instances by `flavor_prefix`. + + include_ai: Include GPU clusters' servers + + include_baremetal: Include bare metal servers. Please, use `GET /v1/bminstances/` instead + + include_k8s: Include managed k8s worker nodes + + ip: An IPv4 address to filter results by. Note: partial matches are allowed. For + example, searching for 192.168.0.1 will return 192.168.0.1, 192.168.0.10, + 192.168.0.110, and so on. + + limit: Optional. Limit the number of returned items + + name: Filter instances by name. You can provide a full or partial name, instances with + matching names will be returned. For example, entering 'test' will return all + instances that contain 'test' in their name. + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + only_isolated: Include only isolated instances + + only_with_fixed_external_ip: Return bare metals only with external fixed IP addresses. + + order_by: Order by field and direction. + + profile_name: Filter result by ddos protection profile name. Effective only with `with_ddos` + set to true. + + protection_status: Filter result by DDoS `protection_status`. if parameter is provided. Effective + only with `with_ddos` set to true. (Active, Queued or Error) + + status: Filters instances by status. + + tag_key_value: Optional. Filter by tag key-value pairs. + + tag_value: Optional. Filter by tag values. ?`tag_value`=value1&`tag_value`=value2 + + type_ddos_profile: Return bare metals either only with advanced or only basic DDoS protection. + Effective only with `with_ddos` set to true. (advanced or basic) + + uuid: Filter the server list result by the UUID of the server. Allowed UUID part + + with_ddos: Include DDoS profile information in the response when set to `true`. Otherwise, + the `ddos_profile` field in the response is `null` by default. + + with_interfaces_name: Include `interface_name` in the addresses + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/instances/{project_id}/{region_id}", + page=AsyncOffsetPage[Instance], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "available_floating": available_floating, + "changes_before": changes_before, + "changes_since": changes_since, + "exclude_flavor_prefix": exclude_flavor_prefix, + "exclude_secgroup": exclude_secgroup, + "flavor_id": flavor_id, + "flavor_prefix": flavor_prefix, + "include_ai": include_ai, + "include_baremetal": include_baremetal, + "include_k8s": include_k8s, + "ip": ip, + "limit": limit, + "name": name, + "offset": offset, + "only_isolated": only_isolated, + "only_with_fixed_external_ip": only_with_fixed_external_ip, + "order_by": order_by, + "profile_name": profile_name, + "protection_status": protection_status, + "status": status, + "tag_key_value": tag_key_value, + "tag_value": tag_value, + "type_ddos_profile": type_ddos_profile, + "uuid": uuid, + "with_ddos": with_ddos, + "with_interfaces_name": with_interfaces_name, + }, + instance_list_params.InstanceListParams, + ), + ), + model=Instance, + ) + + async def delete( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + delete_floatings: bool | Omit = omit, + floatings: str | Omit = omit, + reserved_fixed_ips: str | Omit = omit, + volumes: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete instance + + Args: + project_id: Project ID + + region_id: Region ID + + instance_id: Instance ID + + delete_floatings: True if it is required to delete floating IPs assigned to the instance. Can't be + used with `floatings`. + + floatings: Comma separated list of floating ids that should be deleted. Can't be used with + `delete_floatings`. + + reserved_fixed_ips: Comma separated list of port IDs to be deleted with the instance + + volumes: Comma separated list of volume IDs to be deleted with the instance + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._delete( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "delete_floatings": delete_floatings, + "floatings": floatings, + "reserved_fixed_ips": reserved_fixed_ips, + "volumes": volumes, + }, + instance_delete_params.InstanceDeleteParams, + ), + ), + cast_to=TaskIDList, + ) + + @overload + async def action( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["start"], + activate_profile: Optional[bool] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + The action can be one of: start, stop, reboot, powercycle, suspend or resume. + Suspend and resume are not available for bare metal instances. + + Args: + action: Instance action name + + activate_profile: Used on start instance to activate Advanced DDoS profile + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def action( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["reboot", "reboot_hard", "resume", "stop", "suspend"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + The action can be one of: start, stop, reboot, powercycle, suspend or resume. + Suspend and resume are not available for bare metal instances. + + Args: + action: Instance action name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["action"]) + async def action( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["start"] | Literal["reboot", "reboot_hard", "resume", "stop", "suspend"], + activate_profile: Optional[bool] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._post( + f"/cloud/v2/instances/{project_id}/{region_id}/{instance_id}/action", + body=await async_maybe_transform( + { + "action": action, + "activate_profile": activate_profile, + }, + instance_action_params.InstanceActionParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def add_to_placement_group( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + servergroup_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Add an instance to a server group. + + The instance must not already be in a server + group. Bare metal servers do not support server groups. + + Args: + servergroup_id: Anti-affinity or affinity or soft-anti-affinity server group ID. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/put_into_servergroup", + body=await async_maybe_transform( + {"servergroup_id": servergroup_id}, + instance_add_to_placement_group_params.InstanceAddToPlacementGroupParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def assign_security_group( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + ports_security_group_names: Iterable[instance_assign_security_group_params.PortsSecurityGroupName] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Assign the security group to the server. + + To assign multiple security groups to + all ports, use the NULL value for the `port_id` field + + Args: + name: Security group name, applies to all ports + + ports_security_group_names: Port security groups mapping + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/addsecuritygroup", + body=await async_maybe_transform( + { + "name": name, + "ports_security_group_names": ports_security_group_names, + }, + instance_assign_security_group_params.InstanceAssignSecurityGroupParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def disable_port_security( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InstanceInterface: + """ + Disable port security for instance interface + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return await self._post( + f"/cloud/v1/ports/{project_id}/{region_id}/{port_id}/disable_port_security", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InstanceInterface, + ) + + async def enable_port_security( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InstanceInterface: + """ + Enable port security for instance interface + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return await self._post( + f"/cloud/v1/ports/{project_id}/{region_id}/{port_id}/enable_port_security", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=InstanceInterface, + ) + + async def get( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Instance: + """Retrieve detailed information about a specific instance. + + The response content + language for `ddos_profile` can be controlled via the 'language' cookie + parameter. + + **Cookie Parameters**: + + - `language` (str, optional): Language for the response content. Affects the + `ddos_profile` field. Supported values: + - `'en'` (default) + - `'de'` + - `'ru'` + + Args: + project_id: Project ID + + region_id: Region ID + + instance_id: Instance ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._get( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Instance, + ) + + async def get_console( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + console_type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Console: + """ + Get instance console URL + + Args: + console_type: Console type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._get( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/get_console", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"console_type": console_type}, instance_get_console_params.InstanceGetConsoleParams + ), + ), + cast_to=Console, + ) + + async def remove_from_placement_group( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Remove an instance from its current server group. + + The instance must be in a + server group to be removed. Bare metal servers do not support server groups. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/remove_from_servergroup", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def resize( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Change flavor of the instance + + Args: + flavor_id: Flavor ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/changeflavor", + body=await async_maybe_transform({"flavor_id": flavor_id}, instance_resize_params.InstanceResizeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def unassign_security_group( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + ports_security_group_names: Iterable[instance_unassign_security_group_params.PortsSecurityGroupName] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Un-assign the security group to the server. + + To un-assign multiple security + groups to all ports, use the NULL value for the `port_id` field + + Args: + name: Security group name, applies to all ports + + ports_security_group_names: Port security groups mapping + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/delsecuritygroup", + body=await async_maybe_transform( + { + "name": name, + "ports_security_group_names": ports_security_group_names, + }, + instance_unassign_security_group_params.InstanceUnassignSecurityGroupParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class InstancesResourceWithRawResponse: + def __init__(self, instances: InstancesResource) -> None: + self._instances = instances + + self.create = to_raw_response_wrapper( + instances.create, + ) + self.update = to_raw_response_wrapper( + instances.update, + ) + self.list = to_raw_response_wrapper( + instances.list, + ) + self.delete = to_raw_response_wrapper( + instances.delete, + ) + self.action = to_raw_response_wrapper( + instances.action, + ) + self.add_to_placement_group = to_raw_response_wrapper( + instances.add_to_placement_group, + ) + self.assign_security_group = to_raw_response_wrapper( + instances.assign_security_group, + ) + self.disable_port_security = to_raw_response_wrapper( + instances.disable_port_security, + ) + self.enable_port_security = to_raw_response_wrapper( + instances.enable_port_security, + ) + self.get = to_raw_response_wrapper( + instances.get, + ) + self.get_console = to_raw_response_wrapper( + instances.get_console, + ) + self.remove_from_placement_group = to_raw_response_wrapper( + instances.remove_from_placement_group, + ) + self.resize = to_raw_response_wrapper( + instances.resize, + ) + self.unassign_security_group = to_raw_response_wrapper( + instances.unassign_security_group, + ) + + @cached_property + def flavors(self) -> FlavorsResourceWithRawResponse: + return FlavorsResourceWithRawResponse(self._instances.flavors) + + @cached_property + def interfaces(self) -> InterfacesResourceWithRawResponse: + return InterfacesResourceWithRawResponse(self._instances.interfaces) + + @cached_property + def images(self) -> ImagesResourceWithRawResponse: + return ImagesResourceWithRawResponse(self._instances.images) + + @cached_property + def metrics(self) -> MetricsResourceWithRawResponse: + return MetricsResourceWithRawResponse(self._instances.metrics) + + +class AsyncInstancesResourceWithRawResponse: + def __init__(self, instances: AsyncInstancesResource) -> None: + self._instances = instances + + self.create = async_to_raw_response_wrapper( + instances.create, + ) + self.update = async_to_raw_response_wrapper( + instances.update, + ) + self.list = async_to_raw_response_wrapper( + instances.list, + ) + self.delete = async_to_raw_response_wrapper( + instances.delete, + ) + self.action = async_to_raw_response_wrapper( + instances.action, + ) + self.add_to_placement_group = async_to_raw_response_wrapper( + instances.add_to_placement_group, + ) + self.assign_security_group = async_to_raw_response_wrapper( + instances.assign_security_group, + ) + self.disable_port_security = async_to_raw_response_wrapper( + instances.disable_port_security, + ) + self.enable_port_security = async_to_raw_response_wrapper( + instances.enable_port_security, + ) + self.get = async_to_raw_response_wrapper( + instances.get, + ) + self.get_console = async_to_raw_response_wrapper( + instances.get_console, + ) + self.remove_from_placement_group = async_to_raw_response_wrapper( + instances.remove_from_placement_group, + ) + self.resize = async_to_raw_response_wrapper( + instances.resize, + ) + self.unassign_security_group = async_to_raw_response_wrapper( + instances.unassign_security_group, + ) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithRawResponse: + return AsyncFlavorsResourceWithRawResponse(self._instances.flavors) + + @cached_property + def interfaces(self) -> AsyncInterfacesResourceWithRawResponse: + return AsyncInterfacesResourceWithRawResponse(self._instances.interfaces) + + @cached_property + def images(self) -> AsyncImagesResourceWithRawResponse: + return AsyncImagesResourceWithRawResponse(self._instances.images) + + @cached_property + def metrics(self) -> AsyncMetricsResourceWithRawResponse: + return AsyncMetricsResourceWithRawResponse(self._instances.metrics) + + +class InstancesResourceWithStreamingResponse: + def __init__(self, instances: InstancesResource) -> None: + self._instances = instances + + self.create = to_streamed_response_wrapper( + instances.create, + ) + self.update = to_streamed_response_wrapper( + instances.update, + ) + self.list = to_streamed_response_wrapper( + instances.list, + ) + self.delete = to_streamed_response_wrapper( + instances.delete, + ) + self.action = to_streamed_response_wrapper( + instances.action, + ) + self.add_to_placement_group = to_streamed_response_wrapper( + instances.add_to_placement_group, + ) + self.assign_security_group = to_streamed_response_wrapper( + instances.assign_security_group, + ) + self.disable_port_security = to_streamed_response_wrapper( + instances.disable_port_security, + ) + self.enable_port_security = to_streamed_response_wrapper( + instances.enable_port_security, + ) + self.get = to_streamed_response_wrapper( + instances.get, + ) + self.get_console = to_streamed_response_wrapper( + instances.get_console, + ) + self.remove_from_placement_group = to_streamed_response_wrapper( + instances.remove_from_placement_group, + ) + self.resize = to_streamed_response_wrapper( + instances.resize, + ) + self.unassign_security_group = to_streamed_response_wrapper( + instances.unassign_security_group, + ) + + @cached_property + def flavors(self) -> FlavorsResourceWithStreamingResponse: + return FlavorsResourceWithStreamingResponse(self._instances.flavors) + + @cached_property + def interfaces(self) -> InterfacesResourceWithStreamingResponse: + return InterfacesResourceWithStreamingResponse(self._instances.interfaces) + + @cached_property + def images(self) -> ImagesResourceWithStreamingResponse: + return ImagesResourceWithStreamingResponse(self._instances.images) + + @cached_property + def metrics(self) -> MetricsResourceWithStreamingResponse: + return MetricsResourceWithStreamingResponse(self._instances.metrics) + + +class AsyncInstancesResourceWithStreamingResponse: + def __init__(self, instances: AsyncInstancesResource) -> None: + self._instances = instances + + self.create = async_to_streamed_response_wrapper( + instances.create, + ) + self.update = async_to_streamed_response_wrapper( + instances.update, + ) + self.list = async_to_streamed_response_wrapper( + instances.list, + ) + self.delete = async_to_streamed_response_wrapper( + instances.delete, + ) + self.action = async_to_streamed_response_wrapper( + instances.action, + ) + self.add_to_placement_group = async_to_streamed_response_wrapper( + instances.add_to_placement_group, + ) + self.assign_security_group = async_to_streamed_response_wrapper( + instances.assign_security_group, + ) + self.disable_port_security = async_to_streamed_response_wrapper( + instances.disable_port_security, + ) + self.enable_port_security = async_to_streamed_response_wrapper( + instances.enable_port_security, + ) + self.get = async_to_streamed_response_wrapper( + instances.get, + ) + self.get_console = async_to_streamed_response_wrapper( + instances.get_console, + ) + self.remove_from_placement_group = async_to_streamed_response_wrapper( + instances.remove_from_placement_group, + ) + self.resize = async_to_streamed_response_wrapper( + instances.resize, + ) + self.unassign_security_group = async_to_streamed_response_wrapper( + instances.unassign_security_group, + ) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithStreamingResponse: + return AsyncFlavorsResourceWithStreamingResponse(self._instances.flavors) + + @cached_property + def interfaces(self) -> AsyncInterfacesResourceWithStreamingResponse: + return AsyncInterfacesResourceWithStreamingResponse(self._instances.interfaces) + + @cached_property + def images(self) -> AsyncImagesResourceWithStreamingResponse: + return AsyncImagesResourceWithStreamingResponse(self._instances.images) + + @cached_property + def metrics(self) -> AsyncMetricsResourceWithStreamingResponse: + return AsyncMetricsResourceWithStreamingResponse(self._instances.metrics) diff --git a/src/gcore/resources/cloud/instances/interfaces.py b/src/gcore/resources/cloud/instances/interfaces.py new file mode 100644 index 00000000..53d63c12 --- /dev/null +++ b/src/gcore/resources/cloud/instances/interfaces.py @@ -0,0 +1,801 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, overload + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.instances import interface_attach_params, interface_detach_params +from ....types.cloud.task_id_list import TaskIDList +from ....types.cloud.network_interface_list import NetworkInterfaceList + +__all__ = ["InterfacesResource", "AsyncInterfacesResource"] + + +class InterfacesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> InterfacesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return InterfacesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InterfacesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return InterfacesResourceWithStreamingResponse(self) + + def list( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NetworkInterfaceList: + """ + List all network interfaces attached to the specified instance. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._get( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/interfaces", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NetworkInterfaceList, + ) + + @overload + def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ddos_profile: interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + ip_family: Literal["dual", "ipv4", "ipv6"] | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to instance + + Args: + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + ip_family: Which subnets should be selected: IPv4, IPv6 or use dual stack. + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'external'. Union tag + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + subnet_id: str, + ddos_profile: interface_attach_params.NewInterfaceSpecificSubnetSchemaDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to instance + + Args: + subnet_id: Port will get an IP address from this subnet + + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'subnet' + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + network_id: str, + ddos_profile: interface_attach_params.NewInterfaceAnySubnetSchemaDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + ip_family: Literal["dual", "ipv4", "ipv6"] | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceAnySubnetSchemaSecurityGroup] | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to instance + + Args: + network_id: Port will get an IP address in this network subnet + + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + ip_family: Which subnets should be selected: IPv4, IPv6 or use dual stack. + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'any_subnet' + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + port_id: str, + ddos_profile: interface_attach_params.NewInterfaceReservedFixedIPSchemaDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to instance + + Args: + port_id: Port ID + + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'reserved_fixed_ip'. Union tag + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ddos_profile: interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile + | interface_attach_params.NewInterfaceSpecificSubnetSchemaDDOSProfile + | interface_attach_params.NewInterfaceAnySubnetSchemaDDOSProfile + | interface_attach_params.NewInterfaceReservedFixedIPSchemaDDOSProfile + | Omit = omit, + interface_name: str | Omit = omit, + ip_family: Literal["dual", "ipv4", "ipv6"] | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceAnySubnetSchemaSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] + | Omit = omit, + type: str | Omit = omit, + subnet_id: str | Omit = omit, + network_id: str | Omit = omit, + port_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/attach_interface", + body=maybe_transform( + { + "ddos_profile": ddos_profile, + "interface_name": interface_name, + "ip_family": ip_family, + "port_group": port_group, + "security_groups": security_groups, + "type": type, + "subnet_id": subnet_id, + "network_id": network_id, + "port_id": port_id, + }, + interface_attach_params.InterfaceAttachParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def detach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ip_address: str, + port_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Detach interface from instance + + Args: + ip_address: IP address + + port_id: ID of the port + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/detach_interface", + body=maybe_transform( + { + "ip_address": ip_address, + "port_id": port_id, + }, + interface_detach_params.InterfaceDetachParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncInterfacesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncInterfacesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncInterfacesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInterfacesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncInterfacesResourceWithStreamingResponse(self) + + async def list( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NetworkInterfaceList: + """ + List all network interfaces attached to the specified instance. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._get( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/interfaces", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NetworkInterfaceList, + ) + + @overload + async def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ddos_profile: interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + ip_family: Literal["dual", "ipv4", "ipv6"] | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to instance + + Args: + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + ip_family: Which subnets should be selected: IPv4, IPv6 or use dual stack. + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'external'. Union tag + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + subnet_id: str, + ddos_profile: interface_attach_params.NewInterfaceSpecificSubnetSchemaDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to instance + + Args: + subnet_id: Port will get an IP address from this subnet + + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'subnet' + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + network_id: str, + ddos_profile: interface_attach_params.NewInterfaceAnySubnetSchemaDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + ip_family: Literal["dual", "ipv4", "ipv6"] | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceAnySubnetSchemaSecurityGroup] | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to instance + + Args: + network_id: Port will get an IP address in this network subnet + + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + ip_family: Which subnets should be selected: IPv4, IPv6 or use dual stack. + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'any_subnet' + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + port_id: str, + ddos_profile: interface_attach_params.NewInterfaceReservedFixedIPSchemaDDOSProfile | Omit = omit, + interface_name: str | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] | Omit = omit, + type: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Attach interface to instance + + Args: + port_id: Port ID + + ddos_profile: Advanced DDoS protection. + + interface_name: Interface name + + port_group: Each group will be added to the separate trunk. + + security_groups: List of security group IDs + + type: Must be 'reserved_fixed_ip'. Union tag + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + async def attach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ddos_profile: interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile + | interface_attach_params.NewInterfaceSpecificSubnetSchemaDDOSProfile + | interface_attach_params.NewInterfaceAnySubnetSchemaDDOSProfile + | interface_attach_params.NewInterfaceReservedFixedIPSchemaDDOSProfile + | Omit = omit, + interface_name: str | Omit = omit, + ip_family: Literal["dual", "ipv4", "ipv6"] | Omit = omit, + port_group: int | Omit = omit, + security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceAnySubnetSchemaSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] + | Omit = omit, + type: str | Omit = omit, + subnet_id: str | Omit = omit, + network_id: str | Omit = omit, + port_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/attach_interface", + body=await async_maybe_transform( + { + "ddos_profile": ddos_profile, + "interface_name": interface_name, + "ip_family": ip_family, + "port_group": port_group, + "security_groups": security_groups, + "type": type, + "subnet_id": subnet_id, + "network_id": network_id, + "port_id": port_id, + }, + interface_attach_params.InterfaceAttachParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def detach( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ip_address: str, + port_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Detach interface from instance + + Args: + ip_address: IP address + + port_id: ID of the port + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/detach_interface", + body=await async_maybe_transform( + { + "ip_address": ip_address, + "port_id": port_id, + }, + interface_detach_params.InterfaceDetachParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class InterfacesResourceWithRawResponse: + def __init__(self, interfaces: InterfacesResource) -> None: + self._interfaces = interfaces + + self.list = to_raw_response_wrapper( + interfaces.list, + ) + self.attach = to_raw_response_wrapper( + interfaces.attach, + ) + self.detach = to_raw_response_wrapper( + interfaces.detach, + ) + + +class AsyncInterfacesResourceWithRawResponse: + def __init__(self, interfaces: AsyncInterfacesResource) -> None: + self._interfaces = interfaces + + self.list = async_to_raw_response_wrapper( + interfaces.list, + ) + self.attach = async_to_raw_response_wrapper( + interfaces.attach, + ) + self.detach = async_to_raw_response_wrapper( + interfaces.detach, + ) + + +class InterfacesResourceWithStreamingResponse: + def __init__(self, interfaces: InterfacesResource) -> None: + self._interfaces = interfaces + + self.list = to_streamed_response_wrapper( + interfaces.list, + ) + self.attach = to_streamed_response_wrapper( + interfaces.attach, + ) + self.detach = to_streamed_response_wrapper( + interfaces.detach, + ) + + +class AsyncInterfacesResourceWithStreamingResponse: + def __init__(self, interfaces: AsyncInterfacesResource) -> None: + self._interfaces = interfaces + + self.list = async_to_streamed_response_wrapper( + interfaces.list, + ) + self.attach = async_to_streamed_response_wrapper( + interfaces.attach, + ) + self.detach = async_to_streamed_response_wrapper( + interfaces.detach, + ) diff --git a/src/gcore/resources/cloud/instances/metrics.py b/src/gcore/resources/cloud/instances/metrics.py new file mode 100644 index 00000000..c24b208c --- /dev/null +++ b/src/gcore/resources/cloud/instances/metrics.py @@ -0,0 +1,217 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....types.cloud import InstanceMetricsTimeUnit +from ...._base_client import make_request_options +from ....types.cloud.instances import metric_list_params +from ....types.cloud.instances.metrics_list import MetricsList +from ....types.cloud.instance_metrics_time_unit import InstanceMetricsTimeUnit + +__all__ = ["MetricsResource", "AsyncMetricsResource"] + + +class MetricsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> MetricsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return MetricsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MetricsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return MetricsResourceWithStreamingResponse(self) + + def list( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + time_interval: int, + time_unit: InstanceMetricsTimeUnit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MetricsList: + """ + Get instance metrics, including cpu, memory, network and disk metrics + + Args: + project_id: Project ID + + region_id: Region ID + + instance_id: Instance ID + + time_interval: Time interval. + + time_unit: Time interval unit. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/metrics", + body=maybe_transform( + { + "time_interval": time_interval, + "time_unit": time_unit, + }, + metric_list_params.MetricListParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MetricsList, + ) + + +class AsyncMetricsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncMetricsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncMetricsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMetricsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncMetricsResourceWithStreamingResponse(self) + + async def list( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + time_interval: int, + time_unit: InstanceMetricsTimeUnit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MetricsList: + """ + Get instance metrics, including cpu, memory, network and disk metrics + + Args: + project_id: Project ID + + region_id: Region ID + + instance_id: Instance ID + + time_interval: Time interval. + + time_unit: Time interval unit. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + return await self._post( + f"/cloud/v1/instances/{project_id}/{region_id}/{instance_id}/metrics", + body=await async_maybe_transform( + { + "time_interval": time_interval, + "time_unit": time_unit, + }, + metric_list_params.MetricListParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MetricsList, + ) + + +class MetricsResourceWithRawResponse: + def __init__(self, metrics: MetricsResource) -> None: + self._metrics = metrics + + self.list = to_raw_response_wrapper( + metrics.list, + ) + + +class AsyncMetricsResourceWithRawResponse: + def __init__(self, metrics: AsyncMetricsResource) -> None: + self._metrics = metrics + + self.list = async_to_raw_response_wrapper( + metrics.list, + ) + + +class MetricsResourceWithStreamingResponse: + def __init__(self, metrics: MetricsResource) -> None: + self._metrics = metrics + + self.list = to_streamed_response_wrapper( + metrics.list, + ) + + +class AsyncMetricsResourceWithStreamingResponse: + def __init__(self, metrics: AsyncMetricsResource) -> None: + self._metrics = metrics + + self.list = async_to_streamed_response_wrapper( + metrics.list, + ) diff --git a/src/gcore/resources/cloud/ip_ranges.py b/src/gcore/resources/cloud/ip_ranges.py new file mode 100644 index 00000000..d807001b --- /dev/null +++ b/src/gcore/resources/cloud/ip_ranges.py @@ -0,0 +1,173 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.cloud.ip_ranges import IPRanges + +__all__ = ["IPRangesResource", "AsyncIPRangesResource"] + + +class IPRangesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> IPRangesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return IPRangesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> IPRangesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return IPRangesResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPRanges: + """ + Returns the complete list of IPv4 and IPv6 address ranges that Cloud uses for + outbound (egress) traffic. + + Typical reasons to call this endpoint: + + - Host-file delivery workflows – You upload images or other assets to the Cloud + and share a download link that points to your own infrastructure. Add these + egress prefixes to your firewall or object-storage allow-list so our clients + can fetch the files without being blocked. + - Push integrations / webhooks – You subscribe to the user-actions event log and + Cloud pushes events to your listener endpoint. Whitelisting the egress IP + ranges lets you accept only traffic that originates from us. + - General security controls, audit tooling, or SIEM rules that need to verify + that traffic truly comes from the Cloud. + + The list is global (covers all regions) and refreshed automatically whenever + Gcore allocates new egress IP space. The response is an array of CIDR blocks; + duplicate prefixes are not returned. + """ + return self._get( + "/cloud/public/v1/ipranges/egress", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=IPRanges, + ) + + +class AsyncIPRangesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncIPRangesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncIPRangesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncIPRangesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncIPRangesResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPRanges: + """ + Returns the complete list of IPv4 and IPv6 address ranges that Cloud uses for + outbound (egress) traffic. + + Typical reasons to call this endpoint: + + - Host-file delivery workflows – You upload images or other assets to the Cloud + and share a download link that points to your own infrastructure. Add these + egress prefixes to your firewall or object-storage allow-list so our clients + can fetch the files without being blocked. + - Push integrations / webhooks – You subscribe to the user-actions event log and + Cloud pushes events to your listener endpoint. Whitelisting the egress IP + ranges lets you accept only traffic that originates from us. + - General security controls, audit tooling, or SIEM rules that need to verify + that traffic truly comes from the Cloud. + + The list is global (covers all regions) and refreshed automatically whenever + Gcore allocates new egress IP space. The response is an array of CIDR blocks; + duplicate prefixes are not returned. + """ + return await self._get( + "/cloud/public/v1/ipranges/egress", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=IPRanges, + ) + + +class IPRangesResourceWithRawResponse: + def __init__(self, ip_ranges: IPRangesResource) -> None: + self._ip_ranges = ip_ranges + + self.list = to_raw_response_wrapper( + ip_ranges.list, + ) + + +class AsyncIPRangesResourceWithRawResponse: + def __init__(self, ip_ranges: AsyncIPRangesResource) -> None: + self._ip_ranges = ip_ranges + + self.list = async_to_raw_response_wrapper( + ip_ranges.list, + ) + + +class IPRangesResourceWithStreamingResponse: + def __init__(self, ip_ranges: IPRangesResource) -> None: + self._ip_ranges = ip_ranges + + self.list = to_streamed_response_wrapper( + ip_ranges.list, + ) + + +class AsyncIPRangesResourceWithStreamingResponse: + def __init__(self, ip_ranges: AsyncIPRangesResource) -> None: + self._ip_ranges = ip_ranges + + self.list = async_to_streamed_response_wrapper( + ip_ranges.list, + ) diff --git a/src/gcore/resources/cloud/k8s/__init__.py b/src/gcore/resources/cloud/k8s/__init__.py new file mode 100644 index 00000000..26af76b8 --- /dev/null +++ b/src/gcore/resources/cloud/k8s/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .k8s import ( + K8SResource, + AsyncK8SResource, + K8SResourceWithRawResponse, + AsyncK8SResourceWithRawResponse, + K8SResourceWithStreamingResponse, + AsyncK8SResourceWithStreamingResponse, +) +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from .clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) + +__all__ = [ + "FlavorsResource", + "AsyncFlavorsResource", + "FlavorsResourceWithRawResponse", + "AsyncFlavorsResourceWithRawResponse", + "FlavorsResourceWithStreamingResponse", + "AsyncFlavorsResourceWithStreamingResponse", + "ClustersResource", + "AsyncClustersResource", + "ClustersResourceWithRawResponse", + "AsyncClustersResourceWithRawResponse", + "ClustersResourceWithStreamingResponse", + "AsyncClustersResourceWithStreamingResponse", + "K8SResource", + "AsyncK8SResource", + "K8SResourceWithRawResponse", + "AsyncK8SResourceWithRawResponse", + "K8SResourceWithStreamingResponse", + "AsyncK8SResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/k8s/clusters/__init__.py b/src/gcore/resources/cloud/k8s/clusters/__init__.py new file mode 100644 index 00000000..3da4e5a1 --- /dev/null +++ b/src/gcore/resources/cloud/k8s/clusters/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .nodes import ( + NodesResource, + AsyncNodesResource, + NodesResourceWithRawResponse, + AsyncNodesResourceWithRawResponse, + NodesResourceWithStreamingResponse, + AsyncNodesResourceWithStreamingResponse, +) +from .pools import ( + PoolsResource, + AsyncPoolsResource, + PoolsResourceWithRawResponse, + AsyncPoolsResourceWithRawResponse, + PoolsResourceWithStreamingResponse, + AsyncPoolsResourceWithStreamingResponse, +) +from .clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) + +__all__ = [ + "NodesResource", + "AsyncNodesResource", + "NodesResourceWithRawResponse", + "AsyncNodesResourceWithRawResponse", + "NodesResourceWithStreamingResponse", + "AsyncNodesResourceWithStreamingResponse", + "PoolsResource", + "AsyncPoolsResource", + "PoolsResourceWithRawResponse", + "AsyncPoolsResourceWithRawResponse", + "PoolsResourceWithStreamingResponse", + "AsyncPoolsResourceWithStreamingResponse", + "ClustersResource", + "AsyncClustersResource", + "ClustersResourceWithRawResponse", + "AsyncClustersResourceWithRawResponse", + "ClustersResourceWithStreamingResponse", + "AsyncClustersResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/k8s/clusters/clusters.py b/src/gcore/resources/cloud/k8s/clusters/clusters.py new file mode 100644 index 00000000..ca2c3529 --- /dev/null +++ b/src/gcore/resources/cloud/k8s/clusters/clusters.py @@ -0,0 +1,1519 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable, Optional + +import httpx + +from .nodes import ( + NodesResource, + AsyncNodesResource, + NodesResourceWithRawResponse, + AsyncNodesResourceWithRawResponse, + NodesResourceWithStreamingResponse, + AsyncNodesResourceWithStreamingResponse, +) +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from .pools.pools import ( + PoolsResource, + AsyncPoolsResource, + PoolsResourceWithRawResponse, + AsyncPoolsResourceWithRawResponse, + PoolsResourceWithStreamingResponse, + AsyncPoolsResourceWithStreamingResponse, +) +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.k8s import ( + cluster_create_params, + cluster_delete_params, + cluster_update_params, + cluster_upgrade_params, +) +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.k8s.k8s_cluster import K8SCluster +from .....types.cloud.k8s.k8s_cluster_list import K8SClusterList +from .....types.cloud.k8s_cluster_version_list import K8SClusterVersionList +from .....types.cloud.k8s.k8s_cluster_kubeconfig import K8SClusterKubeconfig +from .....types.cloud.k8s.k8s_cluster_certificate import K8SClusterCertificate + +__all__ = ["ClustersResource", "AsyncClustersResource"] + + +class ClustersResource(SyncAPIResource): + @cached_property + def nodes(self) -> NodesResource: + return NodesResource(self._client) + + @cached_property + def pools(self) -> PoolsResource: + return PoolsResource(self._client) + + @cached_property + def with_raw_response(self) -> ClustersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ClustersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ClustersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ClustersResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + keypair: str, + name: str, + pools: Iterable[cluster_create_params.Pool], + version: str, + add_ons: cluster_create_params.AddOns | Omit = omit, + authentication: Optional[cluster_create_params.Authentication] | Omit = omit, + autoscaler_config: Optional[Dict[str, str]] | Omit = omit, + cni: Optional[cluster_create_params.Cni] | Omit = omit, + csi: cluster_create_params.Csi | Omit = omit, + ddos_profile: Optional[cluster_create_params.DDOSProfile] | Omit = omit, + fixed_network: Optional[str] | Omit = omit, + fixed_subnet: Optional[str] | Omit = omit, + is_ipv6: Optional[bool] | Omit = omit, + logging: Optional[cluster_create_params.Logging] | Omit = omit, + pods_ip_pool: Optional[str] | Omit = omit, + pods_ipv6_pool: Optional[str] | Omit = omit, + services_ip_pool: Optional[str] | Omit = omit, + services_ipv6_pool: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create k8s cluster + + Args: + project_id: Project ID + + region_id: Region ID + + keypair: The keypair of the cluster + + name: The name of the cluster + + pools: The pools of the cluster + + version: The version of the k8s cluster + + add_ons: Cluster add-ons configuration + + authentication: Authentication settings + + autoscaler_config: Cluster autoscaler configuration. + + It allows you to override the default cluster-autoscaler parameters provided by + the platform with your preferred values. + + Supported parameters (in alphabetical order): + + - balance-similar-node-groups (boolean: true/false) - Detect similar node groups + and balance the number of nodes between them. + - expander (string: random, most-pods, least-waste, price, priority, grpc) - + Type of node group expander to be used in scale up. Specifying multiple values + separated by commas will call the expanders in succession until there is only + one option remaining. + - expendable-pods-priority-cutoff (float) - Pods with priority below cutoff will + be expendable. They can be killed without any consideration during scale down + and they don't cause scale up. Pods with null priority (PodPriority disabled) + are non expendable. + - ignore-daemonsets-utilization (boolean: true/false) - Should CA ignore + DaemonSet pods when calculating resource utilization for scaling down. + - max-empty-bulk-delete (integer) - Maximum number of empty nodes that can be + deleted at the same time. + - max-graceful-termination-sec (integer) - Maximum number of seconds CA waits + for pod termination when trying to scale down a node. + - max-node-provision-time (duration: e.g., '15m') - The default maximum time CA + waits for node to be provisioned - the value can be overridden per node group. + - max-total-unready-percentage (float) - Maximum percentage of unready nodes in + the cluster. After this is exceeded, CA halts operations. + - new-pod-scale-up-delay (duration: e.g., '10s') - Pods less than this old will + not be considered for scale-up. Can be increased for individual pods through + annotation. + - ok-total-unready-count (integer) - Number of allowed unready nodes, + irrespective of max-total-unready-percentage. + - scale-down-delay-after-add (duration: e.g., '10m') - How long after scale up + that scale down evaluation resumes. + - scale-down-delay-after-delete (duration: e.g., '10s') - How long after node + deletion that scale down evaluation resumes. + - scale-down-delay-after-failure (duration: e.g., '3m') - How long after scale + down failure that scale down evaluation resumes. + - scale-down-enabled (boolean: true/false) - Should CA scale down the cluster. + - scale-down-unneeded-time (duration: e.g., '10m') - How long a node should be + unneeded before it is eligible for scale down. + - scale-down-unready-time (duration: e.g., '20m') - How long an unready node + should be unneeded before it is eligible for scale down. + - scale-down-utilization-threshold (float) - The maximum value between the sum + of cpu requests and sum of memory requests of all pods running on the node + divided by node's corresponding allocatable resource, below which a node can + be considered for scale down. + - scan-interval (duration: e.g., '10s') - How often cluster is reevaluated for + scale up or down. + - skip-nodes-with-custom-controller-pods (boolean: true/false) - If true cluster + autoscaler will never delete nodes with pods owned by custom controllers. + - skip-nodes-with-local-storage (boolean: true/false) - If true cluster + autoscaler will never delete nodes with pods with local storage, e.g. EmptyDir + or HostPath. + - skip-nodes-with-system-pods (boolean: true/false) - If true cluster autoscaler + will never delete nodes with pods from kube-system (except for DaemonSet or + mirror pods). + + cni: Cluster CNI settings + + csi: Container Storage Interface (CSI) driver settings + + ddos_profile: Advanced DDoS Protection profile + + fixed_network: The network of the cluster + + fixed_subnet: The subnet of the cluster + + is_ipv6: Enable public v6 address + + logging: Logging configuration + + pods_ip_pool: The IP pool for the pods + + pods_ipv6_pool: The IPv6 pool for the pods + + services_ip_pool: The IP pool for the services + + services_ipv6_pool: The IPv6 pool for the services + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}", + body=maybe_transform( + { + "keypair": keypair, + "name": name, + "pools": pools, + "version": version, + "add_ons": add_ons, + "authentication": authentication, + "autoscaler_config": autoscaler_config, + "cni": cni, + "csi": csi, + "ddos_profile": ddos_profile, + "fixed_network": fixed_network, + "fixed_subnet": fixed_subnet, + "is_ipv6": is_ipv6, + "logging": logging, + "pods_ip_pool": pods_ip_pool, + "pods_ipv6_pool": pods_ipv6_pool, + "services_ip_pool": services_ip_pool, + "services_ipv6_pool": services_ipv6_pool, + }, + cluster_create_params.ClusterCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + add_ons: cluster_update_params.AddOns | Omit = omit, + authentication: Optional[cluster_update_params.Authentication] | Omit = omit, + autoscaler_config: Optional[Dict[str, str]] | Omit = omit, + cni: Optional[cluster_update_params.Cni] | Omit = omit, + ddos_profile: Optional[cluster_update_params.DDOSProfile] | Omit = omit, + logging: Optional[cluster_update_params.Logging] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Update k8s cluster + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + add_ons: Cluster add-ons configuration + + authentication: Authentication settings + + autoscaler_config: Cluster autoscaler configuration. + + It allows you to override the default cluster-autoscaler parameters provided by + the platform with your preferred values. + + Supported parameters (in alphabetical order): + + - balance-similar-node-groups (boolean: true/false) - Detect similar node groups + and balance the number of nodes between them. + - expander (string: random, most-pods, least-waste, price, priority, grpc) - + Type of node group expander to be used in scale up. Specifying multiple values + separated by commas will call the expanders in succession until there is only + one option remaining. + - expendable-pods-priority-cutoff (float) - Pods with priority below cutoff will + be expendable. They can be killed without any consideration during scale down + and they don't cause scale up. Pods with null priority (PodPriority disabled) + are non expendable. + - ignore-daemonsets-utilization (boolean: true/false) - Should CA ignore + DaemonSet pods when calculating resource utilization for scaling down. + - max-empty-bulk-delete (integer) - Maximum number of empty nodes that can be + deleted at the same time. + - max-graceful-termination-sec (integer) - Maximum number of seconds CA waits + for pod termination when trying to scale down a node. + - max-node-provision-time (duration: e.g., '15m') - The default maximum time CA + waits for node to be provisioned - the value can be overridden per node group. + - max-total-unready-percentage (float) - Maximum percentage of unready nodes in + the cluster. After this is exceeded, CA halts operations. + - new-pod-scale-up-delay (duration: e.g., '10s') - Pods less than this old will + not be considered for scale-up. Can be increased for individual pods through + annotation. + - ok-total-unready-count (integer) - Number of allowed unready nodes, + irrespective of max-total-unready-percentage. + - scale-down-delay-after-add (duration: e.g., '10m') - How long after scale up + that scale down evaluation resumes. + - scale-down-delay-after-delete (duration: e.g., '10s') - How long after node + deletion that scale down evaluation resumes. + - scale-down-delay-after-failure (duration: e.g., '3m') - How long after scale + down failure that scale down evaluation resumes. + - scale-down-enabled (boolean: true/false) - Should CA scale down the cluster. + - scale-down-unneeded-time (duration: e.g., '10m') - How long a node should be + unneeded before it is eligible for scale down. + - scale-down-unready-time (duration: e.g., '20m') - How long an unready node + should be unneeded before it is eligible for scale down. + - scale-down-utilization-threshold (float) - The maximum value between the sum + of cpu requests and sum of memory requests of all pods running on the node + divided by node's corresponding allocatable resource, below which a node can + be considered for scale down. + - scan-interval (duration: e.g., '10s') - How often cluster is reevaluated for + scale up or down. + - skip-nodes-with-custom-controller-pods (boolean: true/false) - If true cluster + autoscaler will never delete nodes with pods owned by custom controllers. + - skip-nodes-with-local-storage (boolean: true/false) - If true cluster + autoscaler will never delete nodes with pods with local storage, e.g. EmptyDir + or HostPath. + - skip-nodes-with-system-pods (boolean: true/false) - If true cluster autoscaler + will never delete nodes with pods from kube-system (except for DaemonSet or + mirror pods). + + cni: Cluster CNI settings + + ddos_profile: Advanced DDoS Protection profile + + logging: Logging configuration + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return self._patch( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}", + body=maybe_transform( + { + "add_ons": add_ons, + "authentication": authentication, + "autoscaler_config": autoscaler_config, + "cni": cni, + "ddos_profile": ddos_profile, + "logging": logging, + }, + cluster_update_params.ClusterUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterList: + """ + List k8s clusters + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterList, + ) + + def delete( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + volumes: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete k8s cluster + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + volumes: Comma separated list of volume IDs to be deleted with the cluster + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return self._delete( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"volumes": volumes}, cluster_delete_params.ClusterDeleteParams), + ), + cast_to=TaskIDList, + ) + + def get( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SCluster: + """ + Get k8s cluster + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SCluster, + ) + + def get_certificate( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterCertificate: + """ + Get k8s cluster CA certificate + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/certificates", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterCertificate, + ) + + def get_kubeconfig( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterKubeconfig: + """ + Get k8s cluster kubeconfig + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/config", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterKubeconfig, + ) + + def list_versions_for_upgrade( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterVersionList: + """ + List available k8s cluster versions for upgrade + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/upgrade_versions", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterVersionList, + ) + + def upgrade( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + version: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Upgrade k8s cluster + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + version: Target k8s cluster version + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return self._post( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/upgrade", + body=maybe_transform({"version": version}, cluster_upgrade_params.ClusterUpgradeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncClustersResource(AsyncAPIResource): + @cached_property + def nodes(self) -> AsyncNodesResource: + return AsyncNodesResource(self._client) + + @cached_property + def pools(self) -> AsyncPoolsResource: + return AsyncPoolsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncClustersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncClustersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncClustersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncClustersResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + keypair: str, + name: str, + pools: Iterable[cluster_create_params.Pool], + version: str, + add_ons: cluster_create_params.AddOns | Omit = omit, + authentication: Optional[cluster_create_params.Authentication] | Omit = omit, + autoscaler_config: Optional[Dict[str, str]] | Omit = omit, + cni: Optional[cluster_create_params.Cni] | Omit = omit, + csi: cluster_create_params.Csi | Omit = omit, + ddos_profile: Optional[cluster_create_params.DDOSProfile] | Omit = omit, + fixed_network: Optional[str] | Omit = omit, + fixed_subnet: Optional[str] | Omit = omit, + is_ipv6: Optional[bool] | Omit = omit, + logging: Optional[cluster_create_params.Logging] | Omit = omit, + pods_ip_pool: Optional[str] | Omit = omit, + pods_ipv6_pool: Optional[str] | Omit = omit, + services_ip_pool: Optional[str] | Omit = omit, + services_ipv6_pool: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create k8s cluster + + Args: + project_id: Project ID + + region_id: Region ID + + keypair: The keypair of the cluster + + name: The name of the cluster + + pools: The pools of the cluster + + version: The version of the k8s cluster + + add_ons: Cluster add-ons configuration + + authentication: Authentication settings + + autoscaler_config: Cluster autoscaler configuration. + + It allows you to override the default cluster-autoscaler parameters provided by + the platform with your preferred values. + + Supported parameters (in alphabetical order): + + - balance-similar-node-groups (boolean: true/false) - Detect similar node groups + and balance the number of nodes between them. + - expander (string: random, most-pods, least-waste, price, priority, grpc) - + Type of node group expander to be used in scale up. Specifying multiple values + separated by commas will call the expanders in succession until there is only + one option remaining. + - expendable-pods-priority-cutoff (float) - Pods with priority below cutoff will + be expendable. They can be killed without any consideration during scale down + and they don't cause scale up. Pods with null priority (PodPriority disabled) + are non expendable. + - ignore-daemonsets-utilization (boolean: true/false) - Should CA ignore + DaemonSet pods when calculating resource utilization for scaling down. + - max-empty-bulk-delete (integer) - Maximum number of empty nodes that can be + deleted at the same time. + - max-graceful-termination-sec (integer) - Maximum number of seconds CA waits + for pod termination when trying to scale down a node. + - max-node-provision-time (duration: e.g., '15m') - The default maximum time CA + waits for node to be provisioned - the value can be overridden per node group. + - max-total-unready-percentage (float) - Maximum percentage of unready nodes in + the cluster. After this is exceeded, CA halts operations. + - new-pod-scale-up-delay (duration: e.g., '10s') - Pods less than this old will + not be considered for scale-up. Can be increased for individual pods through + annotation. + - ok-total-unready-count (integer) - Number of allowed unready nodes, + irrespective of max-total-unready-percentage. + - scale-down-delay-after-add (duration: e.g., '10m') - How long after scale up + that scale down evaluation resumes. + - scale-down-delay-after-delete (duration: e.g., '10s') - How long after node + deletion that scale down evaluation resumes. + - scale-down-delay-after-failure (duration: e.g., '3m') - How long after scale + down failure that scale down evaluation resumes. + - scale-down-enabled (boolean: true/false) - Should CA scale down the cluster. + - scale-down-unneeded-time (duration: e.g., '10m') - How long a node should be + unneeded before it is eligible for scale down. + - scale-down-unready-time (duration: e.g., '20m') - How long an unready node + should be unneeded before it is eligible for scale down. + - scale-down-utilization-threshold (float) - The maximum value between the sum + of cpu requests and sum of memory requests of all pods running on the node + divided by node's corresponding allocatable resource, below which a node can + be considered for scale down. + - scan-interval (duration: e.g., '10s') - How often cluster is reevaluated for + scale up or down. + - skip-nodes-with-custom-controller-pods (boolean: true/false) - If true cluster + autoscaler will never delete nodes with pods owned by custom controllers. + - skip-nodes-with-local-storage (boolean: true/false) - If true cluster + autoscaler will never delete nodes with pods with local storage, e.g. EmptyDir + or HostPath. + - skip-nodes-with-system-pods (boolean: true/false) - If true cluster autoscaler + will never delete nodes with pods from kube-system (except for DaemonSet or + mirror pods). + + cni: Cluster CNI settings + + csi: Container Storage Interface (CSI) driver settings + + ddos_profile: Advanced DDoS Protection profile + + fixed_network: The network of the cluster + + fixed_subnet: The subnet of the cluster + + is_ipv6: Enable public v6 address + + logging: Logging configuration + + pods_ip_pool: The IP pool for the pods + + pods_ipv6_pool: The IPv6 pool for the pods + + services_ip_pool: The IP pool for the services + + services_ipv6_pool: The IPv6 pool for the services + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "keypair": keypair, + "name": name, + "pools": pools, + "version": version, + "add_ons": add_ons, + "authentication": authentication, + "autoscaler_config": autoscaler_config, + "cni": cni, + "csi": csi, + "ddos_profile": ddos_profile, + "fixed_network": fixed_network, + "fixed_subnet": fixed_subnet, + "is_ipv6": is_ipv6, + "logging": logging, + "pods_ip_pool": pods_ip_pool, + "pods_ipv6_pool": pods_ipv6_pool, + "services_ip_pool": services_ip_pool, + "services_ipv6_pool": services_ipv6_pool, + }, + cluster_create_params.ClusterCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + add_ons: cluster_update_params.AddOns | Omit = omit, + authentication: Optional[cluster_update_params.Authentication] | Omit = omit, + autoscaler_config: Optional[Dict[str, str]] | Omit = omit, + cni: Optional[cluster_update_params.Cni] | Omit = omit, + ddos_profile: Optional[cluster_update_params.DDOSProfile] | Omit = omit, + logging: Optional[cluster_update_params.Logging] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Update k8s cluster + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + add_ons: Cluster add-ons configuration + + authentication: Authentication settings + + autoscaler_config: Cluster autoscaler configuration. + + It allows you to override the default cluster-autoscaler parameters provided by + the platform with your preferred values. + + Supported parameters (in alphabetical order): + + - balance-similar-node-groups (boolean: true/false) - Detect similar node groups + and balance the number of nodes between them. + - expander (string: random, most-pods, least-waste, price, priority, grpc) - + Type of node group expander to be used in scale up. Specifying multiple values + separated by commas will call the expanders in succession until there is only + one option remaining. + - expendable-pods-priority-cutoff (float) - Pods with priority below cutoff will + be expendable. They can be killed without any consideration during scale down + and they don't cause scale up. Pods with null priority (PodPriority disabled) + are non expendable. + - ignore-daemonsets-utilization (boolean: true/false) - Should CA ignore + DaemonSet pods when calculating resource utilization for scaling down. + - max-empty-bulk-delete (integer) - Maximum number of empty nodes that can be + deleted at the same time. + - max-graceful-termination-sec (integer) - Maximum number of seconds CA waits + for pod termination when trying to scale down a node. + - max-node-provision-time (duration: e.g., '15m') - The default maximum time CA + waits for node to be provisioned - the value can be overridden per node group. + - max-total-unready-percentage (float) - Maximum percentage of unready nodes in + the cluster. After this is exceeded, CA halts operations. + - new-pod-scale-up-delay (duration: e.g., '10s') - Pods less than this old will + not be considered for scale-up. Can be increased for individual pods through + annotation. + - ok-total-unready-count (integer) - Number of allowed unready nodes, + irrespective of max-total-unready-percentage. + - scale-down-delay-after-add (duration: e.g., '10m') - How long after scale up + that scale down evaluation resumes. + - scale-down-delay-after-delete (duration: e.g., '10s') - How long after node + deletion that scale down evaluation resumes. + - scale-down-delay-after-failure (duration: e.g., '3m') - How long after scale + down failure that scale down evaluation resumes. + - scale-down-enabled (boolean: true/false) - Should CA scale down the cluster. + - scale-down-unneeded-time (duration: e.g., '10m') - How long a node should be + unneeded before it is eligible for scale down. + - scale-down-unready-time (duration: e.g., '20m') - How long an unready node + should be unneeded before it is eligible for scale down. + - scale-down-utilization-threshold (float) - The maximum value between the sum + of cpu requests and sum of memory requests of all pods running on the node + divided by node's corresponding allocatable resource, below which a node can + be considered for scale down. + - scan-interval (duration: e.g., '10s') - How often cluster is reevaluated for + scale up or down. + - skip-nodes-with-custom-controller-pods (boolean: true/false) - If true cluster + autoscaler will never delete nodes with pods owned by custom controllers. + - skip-nodes-with-local-storage (boolean: true/false) - If true cluster + autoscaler will never delete nodes with pods with local storage, e.g. EmptyDir + or HostPath. + - skip-nodes-with-system-pods (boolean: true/false) - If true cluster autoscaler + will never delete nodes with pods from kube-system (except for DaemonSet or + mirror pods). + + cni: Cluster CNI settings + + ddos_profile: Advanced DDoS Protection profile + + logging: Logging configuration + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return await self._patch( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}", + body=await async_maybe_transform( + { + "add_ons": add_ons, + "authentication": authentication, + "autoscaler_config": autoscaler_config, + "cni": cni, + "ddos_profile": ddos_profile, + "logging": logging, + }, + cluster_update_params.ClusterUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterList: + """ + List k8s clusters + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterList, + ) + + async def delete( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + volumes: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete k8s cluster + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + volumes: Comma separated list of volume IDs to be deleted with the cluster + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return await self._delete( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"volumes": volumes}, cluster_delete_params.ClusterDeleteParams), + ), + cast_to=TaskIDList, + ) + + async def get( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SCluster: + """ + Get k8s cluster + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return await self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SCluster, + ) + + async def get_certificate( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterCertificate: + """ + Get k8s cluster CA certificate + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return await self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/certificates", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterCertificate, + ) + + async def get_kubeconfig( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterKubeconfig: + """ + Get k8s cluster kubeconfig + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return await self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/config", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterKubeconfig, + ) + + async def list_versions_for_upgrade( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterVersionList: + """ + List available k8s cluster versions for upgrade + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return await self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/upgrade_versions", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterVersionList, + ) + + async def upgrade( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + version: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Upgrade k8s cluster + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + version: Target k8s cluster version + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return await self._post( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/upgrade", + body=await async_maybe_transform({"version": version}, cluster_upgrade_params.ClusterUpgradeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class ClustersResourceWithRawResponse: + def __init__(self, clusters: ClustersResource) -> None: + self._clusters = clusters + + self.create = to_raw_response_wrapper( + clusters.create, + ) + self.update = to_raw_response_wrapper( + clusters.update, + ) + self.list = to_raw_response_wrapper( + clusters.list, + ) + self.delete = to_raw_response_wrapper( + clusters.delete, + ) + self.get = to_raw_response_wrapper( + clusters.get, + ) + self.get_certificate = to_raw_response_wrapper( + clusters.get_certificate, + ) + self.get_kubeconfig = to_raw_response_wrapper( + clusters.get_kubeconfig, + ) + self.list_versions_for_upgrade = to_raw_response_wrapper( + clusters.list_versions_for_upgrade, + ) + self.upgrade = to_raw_response_wrapper( + clusters.upgrade, + ) + + @cached_property + def nodes(self) -> NodesResourceWithRawResponse: + return NodesResourceWithRawResponse(self._clusters.nodes) + + @cached_property + def pools(self) -> PoolsResourceWithRawResponse: + return PoolsResourceWithRawResponse(self._clusters.pools) + + +class AsyncClustersResourceWithRawResponse: + def __init__(self, clusters: AsyncClustersResource) -> None: + self._clusters = clusters + + self.create = async_to_raw_response_wrapper( + clusters.create, + ) + self.update = async_to_raw_response_wrapper( + clusters.update, + ) + self.list = async_to_raw_response_wrapper( + clusters.list, + ) + self.delete = async_to_raw_response_wrapper( + clusters.delete, + ) + self.get = async_to_raw_response_wrapper( + clusters.get, + ) + self.get_certificate = async_to_raw_response_wrapper( + clusters.get_certificate, + ) + self.get_kubeconfig = async_to_raw_response_wrapper( + clusters.get_kubeconfig, + ) + self.list_versions_for_upgrade = async_to_raw_response_wrapper( + clusters.list_versions_for_upgrade, + ) + self.upgrade = async_to_raw_response_wrapper( + clusters.upgrade, + ) + + @cached_property + def nodes(self) -> AsyncNodesResourceWithRawResponse: + return AsyncNodesResourceWithRawResponse(self._clusters.nodes) + + @cached_property + def pools(self) -> AsyncPoolsResourceWithRawResponse: + return AsyncPoolsResourceWithRawResponse(self._clusters.pools) + + +class ClustersResourceWithStreamingResponse: + def __init__(self, clusters: ClustersResource) -> None: + self._clusters = clusters + + self.create = to_streamed_response_wrapper( + clusters.create, + ) + self.update = to_streamed_response_wrapper( + clusters.update, + ) + self.list = to_streamed_response_wrapper( + clusters.list, + ) + self.delete = to_streamed_response_wrapper( + clusters.delete, + ) + self.get = to_streamed_response_wrapper( + clusters.get, + ) + self.get_certificate = to_streamed_response_wrapper( + clusters.get_certificate, + ) + self.get_kubeconfig = to_streamed_response_wrapper( + clusters.get_kubeconfig, + ) + self.list_versions_for_upgrade = to_streamed_response_wrapper( + clusters.list_versions_for_upgrade, + ) + self.upgrade = to_streamed_response_wrapper( + clusters.upgrade, + ) + + @cached_property + def nodes(self) -> NodesResourceWithStreamingResponse: + return NodesResourceWithStreamingResponse(self._clusters.nodes) + + @cached_property + def pools(self) -> PoolsResourceWithStreamingResponse: + return PoolsResourceWithStreamingResponse(self._clusters.pools) + + +class AsyncClustersResourceWithStreamingResponse: + def __init__(self, clusters: AsyncClustersResource) -> None: + self._clusters = clusters + + self.create = async_to_streamed_response_wrapper( + clusters.create, + ) + self.update = async_to_streamed_response_wrapper( + clusters.update, + ) + self.list = async_to_streamed_response_wrapper( + clusters.list, + ) + self.delete = async_to_streamed_response_wrapper( + clusters.delete, + ) + self.get = async_to_streamed_response_wrapper( + clusters.get, + ) + self.get_certificate = async_to_streamed_response_wrapper( + clusters.get_certificate, + ) + self.get_kubeconfig = async_to_streamed_response_wrapper( + clusters.get_kubeconfig, + ) + self.list_versions_for_upgrade = async_to_streamed_response_wrapper( + clusters.list_versions_for_upgrade, + ) + self.upgrade = async_to_streamed_response_wrapper( + clusters.upgrade, + ) + + @cached_property + def nodes(self) -> AsyncNodesResourceWithStreamingResponse: + return AsyncNodesResourceWithStreamingResponse(self._clusters.nodes) + + @cached_property + def pools(self) -> AsyncPoolsResourceWithStreamingResponse: + return AsyncPoolsResourceWithStreamingResponse(self._clusters.pools) diff --git a/src/gcore/resources/cloud/k8s/clusters/nodes.py b/src/gcore/resources/cloud/k8s/clusters/nodes.py new file mode 100644 index 00000000..482ece84 --- /dev/null +++ b/src/gcore/resources/cloud/k8s/clusters/nodes.py @@ -0,0 +1,319 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.k8s.clusters import node_list_params +from .....types.cloud.instance_list import InstanceList + +__all__ = ["NodesResource", "AsyncNodesResource"] + + +class NodesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> NodesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return NodesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> NodesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return NodesResourceWithStreamingResponse(self) + + def list( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + with_ddos: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InstanceList: + """ + List k8s cluster nodes + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + with_ddos: Include DDoS profile information if set to true. Default is false. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/instances", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"with_ddos": with_ddos}, node_list_params.NodeListParams), + ), + cast_to=InstanceList, + ) + + def delete( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + After deletion, the node will be automatically recreated to maintain the desired + pool size. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + instance_id: Instance ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/instances/{instance_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncNodesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncNodesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncNodesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncNodesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncNodesResourceWithStreamingResponse(self) + + async def list( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + with_ddos: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InstanceList: + """ + List k8s cluster nodes + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + with_ddos: Include DDoS profile information if set to true. Default is false. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return await self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/instances", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"with_ddos": with_ddos}, node_list_params.NodeListParams), + ), + cast_to=InstanceList, + ) + + async def delete( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + After deletion, the node will be automatically recreated to maintain the desired + pool size. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + instance_id: Instance ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/instances/{instance_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class NodesResourceWithRawResponse: + def __init__(self, nodes: NodesResource) -> None: + self._nodes = nodes + + self.list = to_raw_response_wrapper( + nodes.list, + ) + self.delete = to_raw_response_wrapper( + nodes.delete, + ) + + +class AsyncNodesResourceWithRawResponse: + def __init__(self, nodes: AsyncNodesResource) -> None: + self._nodes = nodes + + self.list = async_to_raw_response_wrapper( + nodes.list, + ) + self.delete = async_to_raw_response_wrapper( + nodes.delete, + ) + + +class NodesResourceWithStreamingResponse: + def __init__(self, nodes: NodesResource) -> None: + self._nodes = nodes + + self.list = to_streamed_response_wrapper( + nodes.list, + ) + self.delete = to_streamed_response_wrapper( + nodes.delete, + ) + + +class AsyncNodesResourceWithStreamingResponse: + def __init__(self, nodes: AsyncNodesResource) -> None: + self._nodes = nodes + + self.list = async_to_streamed_response_wrapper( + nodes.list, + ) + self.delete = async_to_streamed_response_wrapper( + nodes.delete, + ) diff --git a/src/gcore/resources/cloud/k8s/clusters/pools/__init__.py b/src/gcore/resources/cloud/k8s/clusters/pools/__init__.py new file mode 100644 index 00000000..c255bb3b --- /dev/null +++ b/src/gcore/resources/cloud/k8s/clusters/pools/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .nodes import ( + NodesResource, + AsyncNodesResource, + NodesResourceWithRawResponse, + AsyncNodesResourceWithRawResponse, + NodesResourceWithStreamingResponse, + AsyncNodesResourceWithStreamingResponse, +) +from .pools import ( + PoolsResource, + AsyncPoolsResource, + PoolsResourceWithRawResponse, + AsyncPoolsResourceWithRawResponse, + PoolsResourceWithStreamingResponse, + AsyncPoolsResourceWithStreamingResponse, +) + +__all__ = [ + "NodesResource", + "AsyncNodesResource", + "NodesResourceWithRawResponse", + "AsyncNodesResourceWithRawResponse", + "NodesResourceWithStreamingResponse", + "AsyncNodesResourceWithStreamingResponse", + "PoolsResource", + "AsyncPoolsResource", + "PoolsResourceWithRawResponse", + "AsyncPoolsResourceWithRawResponse", + "PoolsResourceWithStreamingResponse", + "AsyncPoolsResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/k8s/clusters/pools/nodes.py b/src/gcore/resources/cloud/k8s/clusters/pools/nodes.py new file mode 100644 index 00000000..5d360e78 --- /dev/null +++ b/src/gcore/resources/cloud/k8s/clusters/pools/nodes.py @@ -0,0 +1,339 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ......_types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ......_utils import maybe_transform, async_maybe_transform +from ......_compat import cached_property +from ......_resource import SyncAPIResource, AsyncAPIResource +from ......_response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ......_base_client import make_request_options +from ......types.cloud.instance_list import InstanceList +from ......types.cloud.k8s.clusters.pools import node_list_params + +__all__ = ["NodesResource", "AsyncNodesResource"] + + +class NodesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> NodesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return NodesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> NodesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return NodesResourceWithStreamingResponse(self) + + def list( + self, + pool_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + with_ddos: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InstanceList: + """ + List k8s cluster pool nodes + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + pool_name: Pool name + + with_ddos: Include DDoS profile information if set to true. Default is false. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not pool_name: + raise ValueError(f"Expected a non-empty value for `pool_name` but received {pool_name!r}") + return self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools/{pool_name}/instances", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"with_ddos": with_ddos}, node_list_params.NodeListParams), + ), + cast_to=InstanceList, + ) + + def delete( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + pool_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + After deletion, the node will be automatically recreated to maintain the desired + pool size. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + pool_name: Pool name + + instance_id: Instance ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not pool_name: + raise ValueError(f"Expected a non-empty value for `pool_name` but received {pool_name!r}") + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools/{pool_name}/instances/{instance_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncNodesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncNodesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncNodesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncNodesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncNodesResourceWithStreamingResponse(self) + + async def list( + self, + pool_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + with_ddos: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> InstanceList: + """ + List k8s cluster pool nodes + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + pool_name: Pool name + + with_ddos: Include DDoS profile information if set to true. Default is false. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not pool_name: + raise ValueError(f"Expected a non-empty value for `pool_name` but received {pool_name!r}") + return await self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools/{pool_name}/instances", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"with_ddos": with_ddos}, node_list_params.NodeListParams), + ), + cast_to=InstanceList, + ) + + async def delete( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + pool_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + After deletion, the node will be automatically recreated to maintain the desired + pool size. + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + pool_name: Pool name + + instance_id: Instance ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not pool_name: + raise ValueError(f"Expected a non-empty value for `pool_name` but received {pool_name!r}") + if not instance_id: + raise ValueError(f"Expected a non-empty value for `instance_id` but received {instance_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools/{pool_name}/instances/{instance_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class NodesResourceWithRawResponse: + def __init__(self, nodes: NodesResource) -> None: + self._nodes = nodes + + self.list = to_raw_response_wrapper( + nodes.list, + ) + self.delete = to_raw_response_wrapper( + nodes.delete, + ) + + +class AsyncNodesResourceWithRawResponse: + def __init__(self, nodes: AsyncNodesResource) -> None: + self._nodes = nodes + + self.list = async_to_raw_response_wrapper( + nodes.list, + ) + self.delete = async_to_raw_response_wrapper( + nodes.delete, + ) + + +class NodesResourceWithStreamingResponse: + def __init__(self, nodes: NodesResource) -> None: + self._nodes = nodes + + self.list = to_streamed_response_wrapper( + nodes.list, + ) + self.delete = to_streamed_response_wrapper( + nodes.delete, + ) + + +class AsyncNodesResourceWithStreamingResponse: + def __init__(self, nodes: AsyncNodesResource) -> None: + self._nodes = nodes + + self.list = async_to_streamed_response_wrapper( + nodes.list, + ) + self.delete = async_to_streamed_response_wrapper( + nodes.delete, + ) diff --git a/src/gcore/resources/cloud/k8s/clusters/pools/pools.py b/src/gcore/resources/cloud/k8s/clusters/pools/pools.py new file mode 100644 index 00000000..d23019c4 --- /dev/null +++ b/src/gcore/resources/cloud/k8s/clusters/pools/pools.py @@ -0,0 +1,1130 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Literal + +import httpx + +from .nodes import ( + NodesResource, + AsyncNodesResource, + NodesResourceWithRawResponse, + AsyncNodesResourceWithRawResponse, + NodesResourceWithStreamingResponse, + AsyncNodesResourceWithStreamingResponse, +) +from ......_types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ......_utils import maybe_transform, async_maybe_transform +from ......_compat import cached_property +from ......_resource import SyncAPIResource, AsyncAPIResource +from ......_response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ......_base_client import make_request_options +from ......types.cloud.k8s.clusters import ( + pool_create_params, + pool_resize_params, + pool_update_params, + pool_check_quota_params, +) +from ......types.cloud.task_id_list import TaskIDList +from ......types.cloud.k8s.clusters.k8s_cluster_pool import K8SClusterPool +from ......types.cloud.k8s.clusters.k8s_cluster_pool_list import K8SClusterPoolList +from ......types.cloud.k8s.clusters.k8s_cluster_pool_quota import K8SClusterPoolQuota + +__all__ = ["PoolsResource", "AsyncPoolsResource"] + + +class PoolsResource(SyncAPIResource): + @cached_property + def nodes(self) -> NodesResource: + return NodesResource(self._client) + + @cached_property + def with_raw_response(self) -> PoolsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return PoolsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PoolsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return PoolsResourceWithStreamingResponse(self) + + def create( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor_id: str, + min_node_count: int, + name: str, + auto_healing_enabled: Optional[bool] | Omit = omit, + boot_volume_size: Optional[int] | Omit = omit, + boot_volume_type: Optional[Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"]] + | Omit = omit, + crio_config: Optional[Dict[str, str]] | Omit = omit, + is_public_ipv4: Optional[bool] | Omit = omit, + kubelet_config: Optional[Dict[str, str]] | Omit = omit, + labels: Optional[Dict[str, str]] | Omit = omit, + max_node_count: Optional[int] | Omit = omit, + servergroup_policy: Optional[Literal["affinity", "anti-affinity", "soft-anti-affinity"]] | Omit = omit, + taints: Optional[Dict[str, str]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create k8s cluster pool + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + flavor_id: Flavor ID + + min_node_count: Minimum node count + + name: Pool's name + + auto_healing_enabled: Enable auto healing + + boot_volume_size: Boot volume size + + boot_volume_type: Boot volume type + + crio_config: Cri-o configuration for pool nodes + + is_public_ipv4: Enable public v4 address + + kubelet_config: Kubelet configuration for pool nodes + + labels: Labels applied to the cluster pool + + max_node_count: Maximum node count + + servergroup_policy: Server group policy: anti-affinity, soft-anti-affinity or affinity + + taints: Taints applied to the cluster pool + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return self._post( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools", + body=maybe_transform( + { + "flavor_id": flavor_id, + "min_node_count": min_node_count, + "name": name, + "auto_healing_enabled": auto_healing_enabled, + "boot_volume_size": boot_volume_size, + "boot_volume_type": boot_volume_type, + "crio_config": crio_config, + "is_public_ipv4": is_public_ipv4, + "kubelet_config": kubelet_config, + "labels": labels, + "max_node_count": max_node_count, + "servergroup_policy": servergroup_policy, + "taints": taints, + }, + pool_create_params.PoolCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + pool_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + auto_healing_enabled: Optional[bool] | Omit = omit, + labels: Optional[Dict[str, str]] | Omit = omit, + max_node_count: Optional[int] | Omit = omit, + min_node_count: Optional[int] | Omit = omit, + node_count: Optional[int] | Omit = omit, + taints: Optional[Dict[str, str]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterPool: + """ + Update k8s cluster pool + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + pool_name: Pool name + + auto_healing_enabled: Enable/disable auto healing + + labels: Labels applied to the cluster pool + + max_node_count: Maximum node count + + min_node_count: Minimum node count + + node_count: This field is deprecated. Please use the cluster pool resize handler instead. + + taints: Taints applied to the cluster pool + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not pool_name: + raise ValueError(f"Expected a non-empty value for `pool_name` but received {pool_name!r}") + return self._patch( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools/{pool_name}", + body=maybe_transform( + { + "auto_healing_enabled": auto_healing_enabled, + "labels": labels, + "max_node_count": max_node_count, + "min_node_count": min_node_count, + "node_count": node_count, + "taints": taints, + }, + pool_update_params.PoolUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterPool, + ) + + def list( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterPoolList: + """ + List k8s cluster pools + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterPoolList, + ) + + def delete( + self, + pool_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete k8s cluster pool + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + pool_name: Pool name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not pool_name: + raise ValueError(f"Expected a non-empty value for `pool_name` but received {pool_name!r}") + return self._delete( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools/{pool_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def check_quota( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor_id: str, + boot_volume_size: Optional[int] | Omit = omit, + max_node_count: Optional[int] | Omit = omit, + min_node_count: Optional[int] | Omit = omit, + name: Optional[str] | Omit = omit, + node_count: Optional[int] | Omit = omit, + servergroup_policy: Optional[Literal["affinity", "anti-affinity", "soft-anti-affinity"]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterPoolQuota: + """Calculate quota requirements for a new cluster pool before creation. + + Returns + exceeded quotas if regional limits would be violated. Use before pool creation + to validate resource availability. Checks: CPU, RAM, volumes, VMs, GPUs, and + baremetal quotas depending on flavor type. + + Args: + project_id: Project ID + + region_id: Region ID + + flavor_id: Flavor ID + + boot_volume_size: Boot volume size + + max_node_count: Maximum node count + + min_node_count: Minimum node count + + name: Name of the cluster pool + + node_count: Maximum node count + + servergroup_policy: Server group policy: anti-affinity, soft-anti-affinity or affinity + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/pools/check_limits", + body=maybe_transform( + { + "flavor_id": flavor_id, + "boot_volume_size": boot_volume_size, + "max_node_count": max_node_count, + "min_node_count": min_node_count, + "name": name, + "node_count": node_count, + "servergroup_policy": servergroup_policy, + }, + pool_check_quota_params.PoolCheckQuotaParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterPoolQuota, + ) + + def get( + self, + pool_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterPool: + """ + Get k8s cluster pool + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + pool_name: Pool name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not pool_name: + raise ValueError(f"Expected a non-empty value for `pool_name` but received {pool_name!r}") + return self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools/{pool_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterPool, + ) + + def resize( + self, + pool_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + node_count: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Resize k8s cluster pool + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + pool_name: Pool name + + node_count: Target node count + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not pool_name: + raise ValueError(f"Expected a non-empty value for `pool_name` but received {pool_name!r}") + return self._post( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools/{pool_name}/resize", + body=maybe_transform({"node_count": node_count}, pool_resize_params.PoolResizeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncPoolsResource(AsyncAPIResource): + @cached_property + def nodes(self) -> AsyncNodesResource: + return AsyncNodesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncPoolsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncPoolsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPoolsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncPoolsResourceWithStreamingResponse(self) + + async def create( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor_id: str, + min_node_count: int, + name: str, + auto_healing_enabled: Optional[bool] | Omit = omit, + boot_volume_size: Optional[int] | Omit = omit, + boot_volume_type: Optional[Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"]] + | Omit = omit, + crio_config: Optional[Dict[str, str]] | Omit = omit, + is_public_ipv4: Optional[bool] | Omit = omit, + kubelet_config: Optional[Dict[str, str]] | Omit = omit, + labels: Optional[Dict[str, str]] | Omit = omit, + max_node_count: Optional[int] | Omit = omit, + servergroup_policy: Optional[Literal["affinity", "anti-affinity", "soft-anti-affinity"]] | Omit = omit, + taints: Optional[Dict[str, str]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create k8s cluster pool + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + flavor_id: Flavor ID + + min_node_count: Minimum node count + + name: Pool's name + + auto_healing_enabled: Enable auto healing + + boot_volume_size: Boot volume size + + boot_volume_type: Boot volume type + + crio_config: Cri-o configuration for pool nodes + + is_public_ipv4: Enable public v4 address + + kubelet_config: Kubelet configuration for pool nodes + + labels: Labels applied to the cluster pool + + max_node_count: Maximum node count + + servergroup_policy: Server group policy: anti-affinity, soft-anti-affinity or affinity + + taints: Taints applied to the cluster pool + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return await self._post( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools", + body=await async_maybe_transform( + { + "flavor_id": flavor_id, + "min_node_count": min_node_count, + "name": name, + "auto_healing_enabled": auto_healing_enabled, + "boot_volume_size": boot_volume_size, + "boot_volume_type": boot_volume_type, + "crio_config": crio_config, + "is_public_ipv4": is_public_ipv4, + "kubelet_config": kubelet_config, + "labels": labels, + "max_node_count": max_node_count, + "servergroup_policy": servergroup_policy, + "taints": taints, + }, + pool_create_params.PoolCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + pool_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + auto_healing_enabled: Optional[bool] | Omit = omit, + labels: Optional[Dict[str, str]] | Omit = omit, + max_node_count: Optional[int] | Omit = omit, + min_node_count: Optional[int] | Omit = omit, + node_count: Optional[int] | Omit = omit, + taints: Optional[Dict[str, str]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterPool: + """ + Update k8s cluster pool + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + pool_name: Pool name + + auto_healing_enabled: Enable/disable auto healing + + labels: Labels applied to the cluster pool + + max_node_count: Maximum node count + + min_node_count: Minimum node count + + node_count: This field is deprecated. Please use the cluster pool resize handler instead. + + taints: Taints applied to the cluster pool + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not pool_name: + raise ValueError(f"Expected a non-empty value for `pool_name` but received {pool_name!r}") + return await self._patch( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools/{pool_name}", + body=await async_maybe_transform( + { + "auto_healing_enabled": auto_healing_enabled, + "labels": labels, + "max_node_count": max_node_count, + "min_node_count": min_node_count, + "node_count": node_count, + "taints": taints, + }, + pool_update_params.PoolUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterPool, + ) + + async def list( + self, + cluster_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterPoolList: + """ + List k8s cluster pools + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + return await self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterPoolList, + ) + + async def delete( + self, + pool_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete k8s cluster pool + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + pool_name: Pool name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not pool_name: + raise ValueError(f"Expected a non-empty value for `pool_name` but received {pool_name!r}") + return await self._delete( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools/{pool_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def check_quota( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor_id: str, + boot_volume_size: Optional[int] | Omit = omit, + max_node_count: Optional[int] | Omit = omit, + min_node_count: Optional[int] | Omit = omit, + name: Optional[str] | Omit = omit, + node_count: Optional[int] | Omit = omit, + servergroup_policy: Optional[Literal["affinity", "anti-affinity", "soft-anti-affinity"]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterPoolQuota: + """Calculate quota requirements for a new cluster pool before creation. + + Returns + exceeded quotas if regional limits would be violated. Use before pool creation + to validate resource availability. Checks: CPU, RAM, volumes, VMs, GPUs, and + baremetal quotas depending on flavor type. + + Args: + project_id: Project ID + + region_id: Region ID + + flavor_id: Flavor ID + + boot_volume_size: Boot volume size + + max_node_count: Maximum node count + + min_node_count: Minimum node count + + name: Name of the cluster pool + + node_count: Maximum node count + + servergroup_policy: Server group policy: anti-affinity, soft-anti-affinity or affinity + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/pools/check_limits", + body=await async_maybe_transform( + { + "flavor_id": flavor_id, + "boot_volume_size": boot_volume_size, + "max_node_count": max_node_count, + "min_node_count": min_node_count, + "name": name, + "node_count": node_count, + "servergroup_policy": servergroup_policy, + }, + pool_check_quota_params.PoolCheckQuotaParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterPoolQuota, + ) + + async def get( + self, + pool_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterPool: + """ + Get k8s cluster pool + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + pool_name: Pool name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not pool_name: + raise ValueError(f"Expected a non-empty value for `pool_name` but received {pool_name!r}") + return await self._get( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools/{pool_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterPool, + ) + + async def resize( + self, + pool_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + cluster_name: str, + node_count: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Resize k8s cluster pool + + Args: + project_id: Project ID + + region_id: Region ID + + cluster_name: Cluster name + + pool_name: Pool name + + node_count: Target node count + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not cluster_name: + raise ValueError(f"Expected a non-empty value for `cluster_name` but received {cluster_name!r}") + if not pool_name: + raise ValueError(f"Expected a non-empty value for `pool_name` but received {pool_name!r}") + return await self._post( + f"/cloud/v2/k8s/clusters/{project_id}/{region_id}/{cluster_name}/pools/{pool_name}/resize", + body=await async_maybe_transform({"node_count": node_count}, pool_resize_params.PoolResizeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class PoolsResourceWithRawResponse: + def __init__(self, pools: PoolsResource) -> None: + self._pools = pools + + self.create = to_raw_response_wrapper( + pools.create, + ) + self.update = to_raw_response_wrapper( + pools.update, + ) + self.list = to_raw_response_wrapper( + pools.list, + ) + self.delete = to_raw_response_wrapper( + pools.delete, + ) + self.check_quota = to_raw_response_wrapper( + pools.check_quota, + ) + self.get = to_raw_response_wrapper( + pools.get, + ) + self.resize = to_raw_response_wrapper( + pools.resize, + ) + + @cached_property + def nodes(self) -> NodesResourceWithRawResponse: + return NodesResourceWithRawResponse(self._pools.nodes) + + +class AsyncPoolsResourceWithRawResponse: + def __init__(self, pools: AsyncPoolsResource) -> None: + self._pools = pools + + self.create = async_to_raw_response_wrapper( + pools.create, + ) + self.update = async_to_raw_response_wrapper( + pools.update, + ) + self.list = async_to_raw_response_wrapper( + pools.list, + ) + self.delete = async_to_raw_response_wrapper( + pools.delete, + ) + self.check_quota = async_to_raw_response_wrapper( + pools.check_quota, + ) + self.get = async_to_raw_response_wrapper( + pools.get, + ) + self.resize = async_to_raw_response_wrapper( + pools.resize, + ) + + @cached_property + def nodes(self) -> AsyncNodesResourceWithRawResponse: + return AsyncNodesResourceWithRawResponse(self._pools.nodes) + + +class PoolsResourceWithStreamingResponse: + def __init__(self, pools: PoolsResource) -> None: + self._pools = pools + + self.create = to_streamed_response_wrapper( + pools.create, + ) + self.update = to_streamed_response_wrapper( + pools.update, + ) + self.list = to_streamed_response_wrapper( + pools.list, + ) + self.delete = to_streamed_response_wrapper( + pools.delete, + ) + self.check_quota = to_streamed_response_wrapper( + pools.check_quota, + ) + self.get = to_streamed_response_wrapper( + pools.get, + ) + self.resize = to_streamed_response_wrapper( + pools.resize, + ) + + @cached_property + def nodes(self) -> NodesResourceWithStreamingResponse: + return NodesResourceWithStreamingResponse(self._pools.nodes) + + +class AsyncPoolsResourceWithStreamingResponse: + def __init__(self, pools: AsyncPoolsResource) -> None: + self._pools = pools + + self.create = async_to_streamed_response_wrapper( + pools.create, + ) + self.update = async_to_streamed_response_wrapper( + pools.update, + ) + self.list = async_to_streamed_response_wrapper( + pools.list, + ) + self.delete = async_to_streamed_response_wrapper( + pools.delete, + ) + self.check_quota = async_to_streamed_response_wrapper( + pools.check_quota, + ) + self.get = async_to_streamed_response_wrapper( + pools.get, + ) + self.resize = async_to_streamed_response_wrapper( + pools.resize, + ) + + @cached_property + def nodes(self) -> AsyncNodesResourceWithStreamingResponse: + return AsyncNodesResourceWithStreamingResponse(self._pools.nodes) diff --git a/src/gcore/resources/cloud/k8s/flavors.py b/src/gcore/resources/cloud/k8s/flavors.py new file mode 100644 index 00000000..36f4fc54 --- /dev/null +++ b/src/gcore/resources/cloud/k8s/flavors.py @@ -0,0 +1,225 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.k8s import flavor_list_params +from ....types.cloud.baremetal_flavor_list import BaremetalFlavorList + +__all__ = ["FlavorsResource", "AsyncFlavorsResource"] + + +class FlavorsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> FlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return FlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return FlavorsResourceWithStreamingResponse(self) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + exclude_gpu: bool | Omit = omit, + include_capacity: bool | Omit = omit, + include_prices: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BaremetalFlavorList: + """Retrieve a list of flavors for k8s pool. + + When the `include_prices` query + parameter is specified, the list shows prices. A client in trial mode gets all + price values as 0. If you get Pricing Error contact the support + + Args: + project_id: Project ID + + region_id: Region ID + + exclude_gpu: Set to true to exclude GPU flavors. Default is false. + + include_capacity: Set to true to include flavor capacity. Default is False. + + include_prices: Set to true to include flavor prices. Default is False. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/k8s/{project_id}/{region_id}/flavors", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "exclude_gpu": exclude_gpu, + "include_capacity": include_capacity, + "include_prices": include_prices, + }, + flavor_list_params.FlavorListParams, + ), + ), + cast_to=BaremetalFlavorList, + ) + + +class AsyncFlavorsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncFlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncFlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncFlavorsResourceWithStreamingResponse(self) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + exclude_gpu: bool | Omit = omit, + include_capacity: bool | Omit = omit, + include_prices: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BaremetalFlavorList: + """Retrieve a list of flavors for k8s pool. + + When the `include_prices` query + parameter is specified, the list shows prices. A client in trial mode gets all + price values as 0. If you get Pricing Error contact the support + + Args: + project_id: Project ID + + region_id: Region ID + + exclude_gpu: Set to true to exclude GPU flavors. Default is false. + + include_capacity: Set to true to include flavor capacity. Default is False. + + include_prices: Set to true to include flavor prices. Default is False. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/k8s/{project_id}/{region_id}/flavors", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "exclude_gpu": exclude_gpu, + "include_capacity": include_capacity, + "include_prices": include_prices, + }, + flavor_list_params.FlavorListParams, + ), + ), + cast_to=BaremetalFlavorList, + ) + + +class FlavorsResourceWithRawResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_raw_response_wrapper( + flavors.list, + ) + + +class AsyncFlavorsResourceWithRawResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_raw_response_wrapper( + flavors.list, + ) + + +class FlavorsResourceWithStreamingResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_streamed_response_wrapper( + flavors.list, + ) + + +class AsyncFlavorsResourceWithStreamingResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_streamed_response_wrapper( + flavors.list, + ) diff --git a/src/gcore/resources/cloud/k8s/k8s.py b/src/gcore/resources/cloud/k8s/k8s.py new file mode 100644 index 00000000..7a31e244 --- /dev/null +++ b/src/gcore/resources/cloud/k8s/k8s.py @@ -0,0 +1,241 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from .clusters.clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) +from ....types.cloud.k8s_cluster_version_list import K8SClusterVersionList + +__all__ = ["K8SResource", "AsyncK8SResource"] + + +class K8SResource(SyncAPIResource): + @cached_property + def flavors(self) -> FlavorsResource: + return FlavorsResource(self._client) + + @cached_property + def clusters(self) -> ClustersResource: + return ClustersResource(self._client) + + @cached_property + def with_raw_response(self) -> K8SResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return K8SResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> K8SResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return K8SResourceWithStreamingResponse(self) + + def list_versions( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterVersionList: + """ + List available k8s cluster versions for creation + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v2/k8s/{project_id}/{region_id}/create_versions", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterVersionList, + ) + + +class AsyncK8SResource(AsyncAPIResource): + @cached_property + def flavors(self) -> AsyncFlavorsResource: + return AsyncFlavorsResource(self._client) + + @cached_property + def clusters(self) -> AsyncClustersResource: + return AsyncClustersResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncK8SResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncK8SResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncK8SResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncK8SResourceWithStreamingResponse(self) + + async def list_versions( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> K8SClusterVersionList: + """ + List available k8s cluster versions for creation + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v2/k8s/{project_id}/{region_id}/create_versions", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=K8SClusterVersionList, + ) + + +class K8SResourceWithRawResponse: + def __init__(self, k8s: K8SResource) -> None: + self._k8s = k8s + + self.list_versions = to_raw_response_wrapper( + k8s.list_versions, + ) + + @cached_property + def flavors(self) -> FlavorsResourceWithRawResponse: + return FlavorsResourceWithRawResponse(self._k8s.flavors) + + @cached_property + def clusters(self) -> ClustersResourceWithRawResponse: + return ClustersResourceWithRawResponse(self._k8s.clusters) + + +class AsyncK8SResourceWithRawResponse: + def __init__(self, k8s: AsyncK8SResource) -> None: + self._k8s = k8s + + self.list_versions = async_to_raw_response_wrapper( + k8s.list_versions, + ) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithRawResponse: + return AsyncFlavorsResourceWithRawResponse(self._k8s.flavors) + + @cached_property + def clusters(self) -> AsyncClustersResourceWithRawResponse: + return AsyncClustersResourceWithRawResponse(self._k8s.clusters) + + +class K8SResourceWithStreamingResponse: + def __init__(self, k8s: K8SResource) -> None: + self._k8s = k8s + + self.list_versions = to_streamed_response_wrapper( + k8s.list_versions, + ) + + @cached_property + def flavors(self) -> FlavorsResourceWithStreamingResponse: + return FlavorsResourceWithStreamingResponse(self._k8s.flavors) + + @cached_property + def clusters(self) -> ClustersResourceWithStreamingResponse: + return ClustersResourceWithStreamingResponse(self._k8s.clusters) + + +class AsyncK8SResourceWithStreamingResponse: + def __init__(self, k8s: AsyncK8SResource) -> None: + self._k8s = k8s + + self.list_versions = async_to_streamed_response_wrapper( + k8s.list_versions, + ) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithStreamingResponse: + return AsyncFlavorsResourceWithStreamingResponse(self._k8s.flavors) + + @cached_property + def clusters(self) -> AsyncClustersResourceWithStreamingResponse: + return AsyncClustersResourceWithStreamingResponse(self._k8s.clusters) diff --git a/src/gcore/resources/cloud/load_balancers/__init__.py b/src/gcore/resources/cloud/load_balancers/__init__.py new file mode 100644 index 00000000..4de45722 --- /dev/null +++ b/src/gcore/resources/cloud/load_balancers/__init__.py @@ -0,0 +1,103 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .pools import ( + PoolsResource, + AsyncPoolsResource, + PoolsResourceWithRawResponse, + AsyncPoolsResourceWithRawResponse, + PoolsResourceWithStreamingResponse, + AsyncPoolsResourceWithStreamingResponse, +) +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from .metrics import ( + MetricsResource, + AsyncMetricsResource, + MetricsResourceWithRawResponse, + AsyncMetricsResourceWithRawResponse, + MetricsResourceWithStreamingResponse, + AsyncMetricsResourceWithStreamingResponse, +) +from .statuses import ( + StatusesResource, + AsyncStatusesResource, + StatusesResourceWithRawResponse, + AsyncStatusesResourceWithRawResponse, + StatusesResourceWithStreamingResponse, + AsyncStatusesResourceWithStreamingResponse, +) +from .listeners import ( + ListenersResource, + AsyncListenersResource, + ListenersResourceWithRawResponse, + AsyncListenersResourceWithRawResponse, + ListenersResourceWithStreamingResponse, + AsyncListenersResourceWithStreamingResponse, +) +from .l7_policies import ( + L7PoliciesResource, + AsyncL7PoliciesResource, + L7PoliciesResourceWithRawResponse, + AsyncL7PoliciesResourceWithRawResponse, + L7PoliciesResourceWithStreamingResponse, + AsyncL7PoliciesResourceWithStreamingResponse, +) +from .load_balancers import ( + LoadBalancersResource, + AsyncLoadBalancersResource, + LoadBalancersResourceWithRawResponse, + AsyncLoadBalancersResourceWithRawResponse, + LoadBalancersResourceWithStreamingResponse, + AsyncLoadBalancersResourceWithStreamingResponse, +) + +__all__ = [ + "L7PoliciesResource", + "AsyncL7PoliciesResource", + "L7PoliciesResourceWithRawResponse", + "AsyncL7PoliciesResourceWithRawResponse", + "L7PoliciesResourceWithStreamingResponse", + "AsyncL7PoliciesResourceWithStreamingResponse", + "FlavorsResource", + "AsyncFlavorsResource", + "FlavorsResourceWithRawResponse", + "AsyncFlavorsResourceWithRawResponse", + "FlavorsResourceWithStreamingResponse", + "AsyncFlavorsResourceWithStreamingResponse", + "ListenersResource", + "AsyncListenersResource", + "ListenersResourceWithRawResponse", + "AsyncListenersResourceWithRawResponse", + "ListenersResourceWithStreamingResponse", + "AsyncListenersResourceWithStreamingResponse", + "PoolsResource", + "AsyncPoolsResource", + "PoolsResourceWithRawResponse", + "AsyncPoolsResourceWithRawResponse", + "PoolsResourceWithStreamingResponse", + "AsyncPoolsResourceWithStreamingResponse", + "MetricsResource", + "AsyncMetricsResource", + "MetricsResourceWithRawResponse", + "AsyncMetricsResourceWithRawResponse", + "MetricsResourceWithStreamingResponse", + "AsyncMetricsResourceWithStreamingResponse", + "StatusesResource", + "AsyncStatusesResource", + "StatusesResourceWithRawResponse", + "AsyncStatusesResourceWithRawResponse", + "StatusesResourceWithStreamingResponse", + "AsyncStatusesResourceWithStreamingResponse", + "LoadBalancersResource", + "AsyncLoadBalancersResource", + "LoadBalancersResourceWithRawResponse", + "AsyncLoadBalancersResourceWithRawResponse", + "LoadBalancersResourceWithStreamingResponse", + "AsyncLoadBalancersResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/load_balancers/flavors.py b/src/gcore/resources/cloud/load_balancers/flavors.py new file mode 100644 index 00000000..df4739a5 --- /dev/null +++ b/src/gcore/resources/cloud/load_balancers/flavors.py @@ -0,0 +1,201 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.load_balancers import flavor_list_params +from ....types.cloud.load_balancer_flavor_list import LoadBalancerFlavorList + +__all__ = ["FlavorsResource", "AsyncFlavorsResource"] + + +class FlavorsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> FlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return FlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return FlavorsResourceWithStreamingResponse(self) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + include_prices: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerFlavorList: + """Retrieve a list of load balancer flavors. + + When the `include_prices` query + parameter is specified, the list shows prices. A client in trial mode gets all + price values as 0. If you get Pricing Error contact the support + + Args: + project_id: Project ID + + region_id: Region ID + + include_prices: Set to true if the response should include flavor prices + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/lbflavors/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"include_prices": include_prices}, flavor_list_params.FlavorListParams), + ), + cast_to=LoadBalancerFlavorList, + ) + + +class AsyncFlavorsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncFlavorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncFlavorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFlavorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncFlavorsResourceWithStreamingResponse(self) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + include_prices: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerFlavorList: + """Retrieve a list of load balancer flavors. + + When the `include_prices` query + parameter is specified, the list shows prices. A client in trial mode gets all + price values as 0. If you get Pricing Error contact the support + + Args: + project_id: Project ID + + region_id: Region ID + + include_prices: Set to true if the response should include flavor prices + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/lbflavors/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"include_prices": include_prices}, flavor_list_params.FlavorListParams + ), + ), + cast_to=LoadBalancerFlavorList, + ) + + +class FlavorsResourceWithRawResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_raw_response_wrapper( + flavors.list, + ) + + +class AsyncFlavorsResourceWithRawResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_raw_response_wrapper( + flavors.list, + ) + + +class FlavorsResourceWithStreamingResponse: + def __init__(self, flavors: FlavorsResource) -> None: + self._flavors = flavors + + self.list = to_streamed_response_wrapper( + flavors.list, + ) + + +class AsyncFlavorsResourceWithStreamingResponse: + def __init__(self, flavors: AsyncFlavorsResource) -> None: + self._flavors = flavors + + self.list = async_to_streamed_response_wrapper( + flavors.list, + ) diff --git a/src/gcore/resources/cloud/load_balancers/l7_policies/__init__.py b/src/gcore/resources/cloud/load_balancers/l7_policies/__init__.py new file mode 100644 index 00000000..fcd15923 --- /dev/null +++ b/src/gcore/resources/cloud/load_balancers/l7_policies/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .rules import ( + RulesResource, + AsyncRulesResource, + RulesResourceWithRawResponse, + AsyncRulesResourceWithRawResponse, + RulesResourceWithStreamingResponse, + AsyncRulesResourceWithStreamingResponse, +) +from .l7_policies import ( + L7PoliciesResource, + AsyncL7PoliciesResource, + L7PoliciesResourceWithRawResponse, + AsyncL7PoliciesResourceWithRawResponse, + L7PoliciesResourceWithStreamingResponse, + AsyncL7PoliciesResourceWithStreamingResponse, +) + +__all__ = [ + "RulesResource", + "AsyncRulesResource", + "RulesResourceWithRawResponse", + "AsyncRulesResourceWithRawResponse", + "RulesResourceWithStreamingResponse", + "AsyncRulesResourceWithStreamingResponse", + "L7PoliciesResource", + "AsyncL7PoliciesResource", + "L7PoliciesResourceWithRawResponse", + "AsyncL7PoliciesResourceWithRawResponse", + "L7PoliciesResourceWithStreamingResponse", + "AsyncL7PoliciesResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/load_balancers/l7_policies/l7_policies.py b/src/gcore/resources/cloud/load_balancers/l7_policies/l7_policies.py new file mode 100644 index 00000000..a814d66b --- /dev/null +++ b/src/gcore/resources/cloud/load_balancers/l7_policies/l7_policies.py @@ -0,0 +1,1477 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, overload + +import httpx + +from .rules import ( + RulesResource, + AsyncRulesResource, + RulesResourceWithRawResponse, + AsyncRulesResourceWithRawResponse, + RulesResourceWithStreamingResponse, + AsyncRulesResourceWithStreamingResponse, +) +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ....._utils import required_args, maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.load_balancers import l7_policy_create_params, l7_policy_update_params +from .....types.cloud.load_balancer_l7_policy import LoadBalancerL7Policy +from .....types.cloud.load_balancer_l7_policy_list import LoadBalancerL7PolicyList + +__all__ = ["L7PoliciesResource", "AsyncL7PoliciesResource"] + + +class L7PoliciesResource(SyncAPIResource): + @cached_property + def rules(self) -> RulesResource: + return RulesResource(self._client) + + @cached_property + def with_raw_response(self) -> L7PoliciesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return L7PoliciesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> L7PoliciesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return L7PoliciesResourceWithStreamingResponse(self) + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_TO_URL"], + listener_id: str, + redirect_url: str, + name: str | Omit = omit, + position: int | Omit = omit, + redirect_http_code: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer L7 policy + + Args: + project_id: Project ID + + region_id: Region ID + + action: Action + + listener_id: Listener ID + + redirect_url: Requests matching this policy will be redirected to this URL. + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + redirect_http_code: Requests matching this policy will be redirected to the specified URL or Prefix + URL with the HTTP response code. Valid options are 301, 302, 303, 307, or 308. + Default is 302. + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_PREFIX"], + listener_id: str, + redirect_prefix: str, + name: str | Omit = omit, + position: int | Omit = omit, + redirect_http_code: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer L7 policy + + Args: + project_id: Project ID + + region_id: Region ID + + action: Action + + listener_id: Listener ID + + redirect_prefix: Requests matching this policy will be redirected to this Prefix URL. + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + redirect_http_code: Requests matching this policy will be redirected to the specified URL or Prefix + URL with the HTTP response code. Valid options are 301, 302, 303, 307, or 308. + Default is 302. + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_TO_POOL"], + listener_id: str, + redirect_pool_id: str, + name: str | Omit = omit, + position: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer L7 policy + + Args: + project_id: Project ID + + region_id: Region ID + + action: Action + + listener_id: Listener ID + + redirect_pool_id: Requests matching this policy will be redirected to the pool with this ID. + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REJECT"], + listener_id: str, + name: str | Omit = omit, + position: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer L7 policy + + Args: + project_id: Project ID + + region_id: Region ID + + action: Action + + listener_id: Listener ID + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args( + ["action", "listener_id", "redirect_url"], + ["action", "listener_id", "redirect_prefix"], + ["action", "listener_id", "redirect_pool_id"], + ["action", "listener_id"], + ) + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_TO_URL"] + | Literal["REDIRECT_PREFIX"] + | Literal["REDIRECT_TO_POOL"] + | Literal["REJECT"], + listener_id: str, + redirect_url: str | Omit = omit, + name: str | Omit = omit, + position: int | Omit = omit, + redirect_http_code: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + redirect_prefix: str | Omit = omit, + redirect_pool_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/l7policies/{project_id}/{region_id}", + body=maybe_transform( + { + "action": action, + "listener_id": listener_id, + "redirect_url": redirect_url, + "name": name, + "position": position, + "redirect_http_code": redirect_http_code, + "tags": tags, + "redirect_prefix": redirect_prefix, + "redirect_pool_id": redirect_pool_id, + }, + l7_policy_create_params.L7PolicyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + @overload + def update( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_TO_URL"], + redirect_url: str, + name: str | Omit = omit, + position: int | Omit = omit, + redirect_http_code: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Updates only provided fields; omitted ones stay unchanged. + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + action: Action + + redirect_url: Requests matching this policy will be redirected to this URL. Only valid if + action is `REDIRECT_TO_URL`. + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + redirect_http_code: Requests matching this policy will be redirected to the specified URL or Prefix + URL with the HTTP response code. Valid if action is `REDIRECT_TO_URL` or + `REDIRECT_PREFIX`. Valid options are 301, 302, 303, 307, or 308. Default is 302. + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def update( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_PREFIX"], + redirect_prefix: str, + name: str | Omit = omit, + position: int | Omit = omit, + redirect_http_code: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Updates only provided fields; omitted ones stay unchanged. + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + action: Action + + redirect_prefix: Requests matching this policy will be redirected to this Prefix URL. + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + redirect_http_code: Requests matching this policy will be redirected to the specified URL or Prefix + URL with the HTTP response code. Valid options are 301, 302, 303, 307, or 308. + Default is 302. + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def update( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_TO_POOL"], + redirect_pool_id: str, + name: str | Omit = omit, + position: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Updates only provided fields; omitted ones stay unchanged. + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + action: Action + + redirect_pool_id: Requests matching this policy will be redirected to the pool with this ID. + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def update( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REJECT"], + name: str | Omit = omit, + position: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Updates only provided fields; omitted ones stay unchanged. + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + action: Action + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args( + ["action", "redirect_url"], ["action", "redirect_prefix"], ["action", "redirect_pool_id"], ["action"] + ) + def update( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_TO_URL"] + | Literal["REDIRECT_PREFIX"] + | Literal["REDIRECT_TO_POOL"] + | Literal["REJECT"], + redirect_url: str | Omit = omit, + name: str | Omit = omit, + position: int | Omit = omit, + redirect_http_code: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + redirect_prefix: str | Omit = omit, + redirect_pool_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + return self._patch( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}", + body=maybe_transform( + { + "action": action, + "redirect_url": redirect_url, + "name": name, + "position": position, + "redirect_http_code": redirect_http_code, + "tags": tags, + "redirect_prefix": redirect_prefix, + "redirect_pool_id": redirect_pool_id, + }, + l7_policy_update_params.L7PolicyUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerL7PolicyList: + """ + List load balancer L7 policies + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/l7policies/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerL7PolicyList, + ) + + def delete( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete load balancer L7 policy + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + return self._delete( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerL7Policy: + """ + Get load balancer L7 policy + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + return self._get( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerL7Policy, + ) + + +class AsyncL7PoliciesResource(AsyncAPIResource): + @cached_property + def rules(self) -> AsyncRulesResource: + return AsyncRulesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncL7PoliciesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncL7PoliciesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncL7PoliciesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncL7PoliciesResourceWithStreamingResponse(self) + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_TO_URL"], + listener_id: str, + redirect_url: str, + name: str | Omit = omit, + position: int | Omit = omit, + redirect_http_code: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer L7 policy + + Args: + project_id: Project ID + + region_id: Region ID + + action: Action + + listener_id: Listener ID + + redirect_url: Requests matching this policy will be redirected to this URL. + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + redirect_http_code: Requests matching this policy will be redirected to the specified URL or Prefix + URL with the HTTP response code. Valid options are 301, 302, 303, 307, or 308. + Default is 302. + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_PREFIX"], + listener_id: str, + redirect_prefix: str, + name: str | Omit = omit, + position: int | Omit = omit, + redirect_http_code: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer L7 policy + + Args: + project_id: Project ID + + region_id: Region ID + + action: Action + + listener_id: Listener ID + + redirect_prefix: Requests matching this policy will be redirected to this Prefix URL. + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + redirect_http_code: Requests matching this policy will be redirected to the specified URL or Prefix + URL with the HTTP response code. Valid options are 301, 302, 303, 307, or 308. + Default is 302. + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_TO_POOL"], + listener_id: str, + redirect_pool_id: str, + name: str | Omit = omit, + position: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer L7 policy + + Args: + project_id: Project ID + + region_id: Region ID + + action: Action + + listener_id: Listener ID + + redirect_pool_id: Requests matching this policy will be redirected to the pool with this ID. + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REJECT"], + listener_id: str, + name: str | Omit = omit, + position: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer L7 policy + + Args: + project_id: Project ID + + region_id: Region ID + + action: Action + + listener_id: Listener ID + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args( + ["action", "listener_id", "redirect_url"], + ["action", "listener_id", "redirect_prefix"], + ["action", "listener_id", "redirect_pool_id"], + ["action", "listener_id"], + ) + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_TO_URL"] + | Literal["REDIRECT_PREFIX"] + | Literal["REDIRECT_TO_POOL"] + | Literal["REJECT"], + listener_id: str, + redirect_url: str | Omit = omit, + name: str | Omit = omit, + position: int | Omit = omit, + redirect_http_code: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + redirect_prefix: str | Omit = omit, + redirect_pool_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/l7policies/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "action": action, + "listener_id": listener_id, + "redirect_url": redirect_url, + "name": name, + "position": position, + "redirect_http_code": redirect_http_code, + "tags": tags, + "redirect_prefix": redirect_prefix, + "redirect_pool_id": redirect_pool_id, + }, + l7_policy_create_params.L7PolicyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + @overload + async def update( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_TO_URL"], + redirect_url: str, + name: str | Omit = omit, + position: int | Omit = omit, + redirect_http_code: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Updates only provided fields; omitted ones stay unchanged. + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + action: Action + + redirect_url: Requests matching this policy will be redirected to this URL. Only valid if + action is `REDIRECT_TO_URL`. + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + redirect_http_code: Requests matching this policy will be redirected to the specified URL or Prefix + URL with the HTTP response code. Valid if action is `REDIRECT_TO_URL` or + `REDIRECT_PREFIX`. Valid options are 301, 302, 303, 307, or 308. Default is 302. + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def update( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_PREFIX"], + redirect_prefix: str, + name: str | Omit = omit, + position: int | Omit = omit, + redirect_http_code: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Updates only provided fields; omitted ones stay unchanged. + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + action: Action + + redirect_prefix: Requests matching this policy will be redirected to this Prefix URL. + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + redirect_http_code: Requests matching this policy will be redirected to the specified URL or Prefix + URL with the HTTP response code. Valid options are 301, 302, 303, 307, or 308. + Default is 302. + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def update( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_TO_POOL"], + redirect_pool_id: str, + name: str | Omit = omit, + position: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Updates only provided fields; omitted ones stay unchanged. + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + action: Action + + redirect_pool_id: Requests matching this policy will be redirected to the pool with this ID. + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def update( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REJECT"], + name: str | Omit = omit, + position: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Updates only provided fields; omitted ones stay unchanged. + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + action: Action + + name: Human-readable name of the policy + + position: The position of this policy on the listener + + tags: A list of simple strings assigned to the resource. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args( + ["action", "redirect_url"], ["action", "redirect_prefix"], ["action", "redirect_pool_id"], ["action"] + ) + async def update( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["REDIRECT_TO_URL"] + | Literal["REDIRECT_PREFIX"] + | Literal["REDIRECT_TO_POOL"] + | Literal["REJECT"], + redirect_url: str | Omit = omit, + name: str | Omit = omit, + position: int | Omit = omit, + redirect_http_code: int | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + redirect_prefix: str | Omit = omit, + redirect_pool_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + return await self._patch( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}", + body=await async_maybe_transform( + { + "action": action, + "redirect_url": redirect_url, + "name": name, + "position": position, + "redirect_http_code": redirect_http_code, + "tags": tags, + "redirect_prefix": redirect_prefix, + "redirect_pool_id": redirect_pool_id, + }, + l7_policy_update_params.L7PolicyUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerL7PolicyList: + """ + List load balancer L7 policies + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/l7policies/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerL7PolicyList, + ) + + async def delete( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete load balancer L7 policy + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + return await self._delete( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerL7Policy: + """ + Get load balancer L7 policy + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + return await self._get( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerL7Policy, + ) + + +class L7PoliciesResourceWithRawResponse: + def __init__(self, l7_policies: L7PoliciesResource) -> None: + self._l7_policies = l7_policies + + self.create = to_raw_response_wrapper( + l7_policies.create, + ) + self.update = to_raw_response_wrapper( + l7_policies.update, + ) + self.list = to_raw_response_wrapper( + l7_policies.list, + ) + self.delete = to_raw_response_wrapper( + l7_policies.delete, + ) + self.get = to_raw_response_wrapper( + l7_policies.get, + ) + + @cached_property + def rules(self) -> RulesResourceWithRawResponse: + return RulesResourceWithRawResponse(self._l7_policies.rules) + + +class AsyncL7PoliciesResourceWithRawResponse: + def __init__(self, l7_policies: AsyncL7PoliciesResource) -> None: + self._l7_policies = l7_policies + + self.create = async_to_raw_response_wrapper( + l7_policies.create, + ) + self.update = async_to_raw_response_wrapper( + l7_policies.update, + ) + self.list = async_to_raw_response_wrapper( + l7_policies.list, + ) + self.delete = async_to_raw_response_wrapper( + l7_policies.delete, + ) + self.get = async_to_raw_response_wrapper( + l7_policies.get, + ) + + @cached_property + def rules(self) -> AsyncRulesResourceWithRawResponse: + return AsyncRulesResourceWithRawResponse(self._l7_policies.rules) + + +class L7PoliciesResourceWithStreamingResponse: + def __init__(self, l7_policies: L7PoliciesResource) -> None: + self._l7_policies = l7_policies + + self.create = to_streamed_response_wrapper( + l7_policies.create, + ) + self.update = to_streamed_response_wrapper( + l7_policies.update, + ) + self.list = to_streamed_response_wrapper( + l7_policies.list, + ) + self.delete = to_streamed_response_wrapper( + l7_policies.delete, + ) + self.get = to_streamed_response_wrapper( + l7_policies.get, + ) + + @cached_property + def rules(self) -> RulesResourceWithStreamingResponse: + return RulesResourceWithStreamingResponse(self._l7_policies.rules) + + +class AsyncL7PoliciesResourceWithStreamingResponse: + def __init__(self, l7_policies: AsyncL7PoliciesResource) -> None: + self._l7_policies = l7_policies + + self.create = async_to_streamed_response_wrapper( + l7_policies.create, + ) + self.update = async_to_streamed_response_wrapper( + l7_policies.update, + ) + self.list = async_to_streamed_response_wrapper( + l7_policies.list, + ) + self.delete = async_to_streamed_response_wrapper( + l7_policies.delete, + ) + self.get = async_to_streamed_response_wrapper( + l7_policies.get, + ) + + @cached_property + def rules(self) -> AsyncRulesResourceWithStreamingResponse: + return AsyncRulesResourceWithStreamingResponse(self._l7_policies.rules) diff --git a/src/gcore/resources/cloud/load_balancers/l7_policies/rules.py b/src/gcore/resources/cloud/load_balancers/l7_policies/rules.py new file mode 100644 index 00000000..c8591644 --- /dev/null +++ b/src/gcore/resources/cloud/load_balancers/l7_policies/rules.py @@ -0,0 +1,785 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.load_balancer_l7_rule import LoadBalancerL7Rule +from .....types.cloud.load_balancer_l7_rule_list import LoadBalancerL7RuleList +from .....types.cloud.load_balancers.l7_policies import rule_create_params, rule_replace_params + +__all__ = ["RulesResource", "AsyncRulesResource"] + + +class RulesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return RulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return RulesResourceWithStreamingResponse(self) + + def create( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + compare_type: Literal["CONTAINS", "ENDS_WITH", "EQUAL_TO", "REGEX", "STARTS_WITH"], + type: Literal[ + "COOKIE", + "FILE_TYPE", + "HEADER", + "HOST_NAME", + "PATH", + "SSL_CONN_HAS_CERT", + "SSL_DN_FIELD", + "SSL_VERIFY_RESULT", + ], + value: str, + invert: bool | Omit = omit, + key: str | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer L7 rule + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + compare_type: The comparison type for the L7 rule + + type: The L7 rule type + + value: The value to use for the comparison + + invert: When true the logic of the rule is inverted. + + key: The key to use for the comparison. Required for COOKIE and HEADER `type` only. + + tags: A list of simple strings assigned to the l7 rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + return self._post( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}/rules", + body=maybe_transform( + { + "compare_type": compare_type, + "type": type, + "value": value, + "invert": invert, + "key": key, + "tags": tags, + }, + rule_create_params.RuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerL7RuleList: + """ + List load balancer L7 policy rules + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + return self._get( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}/rules", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerL7RuleList, + ) + + def delete( + self, + l7rule_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + l7policy_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete load balancer L7 rule + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + l7rule_id: L7 rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + if not l7rule_id: + raise ValueError(f"Expected a non-empty value for `l7rule_id` but received {l7rule_id!r}") + return self._delete( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}/rules/{l7rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + l7rule_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + l7policy_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerL7Rule: + """ + Get load balancer L7 rule + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + l7rule_id: L7 rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + if not l7rule_id: + raise ValueError(f"Expected a non-empty value for `l7rule_id` but received {l7rule_id!r}") + return self._get( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}/rules/{l7rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerL7Rule, + ) + + def replace( + self, + l7rule_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + l7policy_id: str, + compare_type: Literal["CONTAINS", "ENDS_WITH", "EQUAL_TO", "REGEX", "STARTS_WITH"], + invert: bool | Omit = omit, + key: str | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + type: Literal[ + "COOKIE", + "FILE_TYPE", + "HEADER", + "HOST_NAME", + "PATH", + "SSL_CONN_HAS_CERT", + "SSL_DN_FIELD", + "SSL_VERIFY_RESULT", + ] + | Omit = omit, + value: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Replace load balancer L7 rule properties + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + l7rule_id: L7 rule ID + + compare_type: The comparison type for the L7 rule + + invert: When true the logic of the rule is inverted. + + key: The key to use for the comparison. Required for COOKIE and HEADER `type` only. + + tags: A list of simple strings assigned to the l7 rule + + type: The L7 rule type + + value: The value to use for the comparison + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + if not l7rule_id: + raise ValueError(f"Expected a non-empty value for `l7rule_id` but received {l7rule_id!r}") + return self._put( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}/rules/{l7rule_id}", + body=maybe_transform( + { + "compare_type": compare_type, + "invert": invert, + "key": key, + "tags": tags, + "type": type, + "value": value, + }, + rule_replace_params.RuleReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncRulesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncRulesResourceWithStreamingResponse(self) + + async def create( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + compare_type: Literal["CONTAINS", "ENDS_WITH", "EQUAL_TO", "REGEX", "STARTS_WITH"], + type: Literal[ + "COOKIE", + "FILE_TYPE", + "HEADER", + "HOST_NAME", + "PATH", + "SSL_CONN_HAS_CERT", + "SSL_DN_FIELD", + "SSL_VERIFY_RESULT", + ], + value: str, + invert: bool | Omit = omit, + key: str | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer L7 rule + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + compare_type: The comparison type for the L7 rule + + type: The L7 rule type + + value: The value to use for the comparison + + invert: When true the logic of the rule is inverted. + + key: The key to use for the comparison. Required for COOKIE and HEADER `type` only. + + tags: A list of simple strings assigned to the l7 rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + return await self._post( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}/rules", + body=await async_maybe_transform( + { + "compare_type": compare_type, + "type": type, + "value": value, + "invert": invert, + "key": key, + "tags": tags, + }, + rule_create_params.RuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def list( + self, + l7policy_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerL7RuleList: + """ + List load balancer L7 policy rules + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + return await self._get( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}/rules", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerL7RuleList, + ) + + async def delete( + self, + l7rule_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + l7policy_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete load balancer L7 rule + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + l7rule_id: L7 rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + if not l7rule_id: + raise ValueError(f"Expected a non-empty value for `l7rule_id` but received {l7rule_id!r}") + return await self._delete( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}/rules/{l7rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + l7rule_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + l7policy_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerL7Rule: + """ + Get load balancer L7 rule + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + l7rule_id: L7 rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + if not l7rule_id: + raise ValueError(f"Expected a non-empty value for `l7rule_id` but received {l7rule_id!r}") + return await self._get( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}/rules/{l7rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerL7Rule, + ) + + async def replace( + self, + l7rule_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + l7policy_id: str, + compare_type: Literal["CONTAINS", "ENDS_WITH", "EQUAL_TO", "REGEX", "STARTS_WITH"], + invert: bool | Omit = omit, + key: str | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + type: Literal[ + "COOKIE", + "FILE_TYPE", + "HEADER", + "HOST_NAME", + "PATH", + "SSL_CONN_HAS_CERT", + "SSL_DN_FIELD", + "SSL_VERIFY_RESULT", + ] + | Omit = omit, + value: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Replace load balancer L7 rule properties + + Args: + project_id: Project ID + + region_id: Region ID + + l7policy_id: L7 policy ID + + l7rule_id: L7 rule ID + + compare_type: The comparison type for the L7 rule + + invert: When true the logic of the rule is inverted. + + key: The key to use for the comparison. Required for COOKIE and HEADER `type` only. + + tags: A list of simple strings assigned to the l7 rule + + type: The L7 rule type + + value: The value to use for the comparison + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not l7policy_id: + raise ValueError(f"Expected a non-empty value for `l7policy_id` but received {l7policy_id!r}") + if not l7rule_id: + raise ValueError(f"Expected a non-empty value for `l7rule_id` but received {l7rule_id!r}") + return await self._put( + f"/cloud/v1/l7policies/{project_id}/{region_id}/{l7policy_id}/rules/{l7rule_id}", + body=await async_maybe_transform( + { + "compare_type": compare_type, + "invert": invert, + "key": key, + "tags": tags, + "type": type, + "value": value, + }, + rule_replace_params.RuleReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class RulesResourceWithRawResponse: + def __init__(self, rules: RulesResource) -> None: + self._rules = rules + + self.create = to_raw_response_wrapper( + rules.create, + ) + self.list = to_raw_response_wrapper( + rules.list, + ) + self.delete = to_raw_response_wrapper( + rules.delete, + ) + self.get = to_raw_response_wrapper( + rules.get, + ) + self.replace = to_raw_response_wrapper( + rules.replace, + ) + + +class AsyncRulesResourceWithRawResponse: + def __init__(self, rules: AsyncRulesResource) -> None: + self._rules = rules + + self.create = async_to_raw_response_wrapper( + rules.create, + ) + self.list = async_to_raw_response_wrapper( + rules.list, + ) + self.delete = async_to_raw_response_wrapper( + rules.delete, + ) + self.get = async_to_raw_response_wrapper( + rules.get, + ) + self.replace = async_to_raw_response_wrapper( + rules.replace, + ) + + +class RulesResourceWithStreamingResponse: + def __init__(self, rules: RulesResource) -> None: + self._rules = rules + + self.create = to_streamed_response_wrapper( + rules.create, + ) + self.list = to_streamed_response_wrapper( + rules.list, + ) + self.delete = to_streamed_response_wrapper( + rules.delete, + ) + self.get = to_streamed_response_wrapper( + rules.get, + ) + self.replace = to_streamed_response_wrapper( + rules.replace, + ) + + +class AsyncRulesResourceWithStreamingResponse: + def __init__(self, rules: AsyncRulesResource) -> None: + self._rules = rules + + self.create = async_to_streamed_response_wrapper( + rules.create, + ) + self.list = async_to_streamed_response_wrapper( + rules.list, + ) + self.delete = async_to_streamed_response_wrapper( + rules.delete, + ) + self.get = async_to_streamed_response_wrapper( + rules.get, + ) + self.replace = async_to_streamed_response_wrapper( + rules.replace, + ) diff --git a/src/gcore/resources/cloud/load_balancers/listeners.py b/src/gcore/resources/cloud/load_balancers/listeners.py new file mode 100644 index 00000000..6dc71737 --- /dev/null +++ b/src/gcore/resources/cloud/load_balancers/listeners.py @@ -0,0 +1,892 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....types.cloud import LbListenerProtocol +from ...._base_client import make_request_options +from ....types.cloud.task_id_list import TaskIDList +from ....types.cloud.load_balancers import ( + listener_get_params, + listener_list_params, + listener_create_params, + listener_delete_params, + listener_update_params, +) +from ....types.cloud.lb_listener_protocol import LbListenerProtocol +from ....types.cloud.load_balancer_listener_list import LoadBalancerListenerList +from ....types.cloud.load_balancer_listener_detail import LoadBalancerListenerDetail + +__all__ = ["ListenersResource", "AsyncListenersResource"] + + +class ListenersResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ListenersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ListenersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ListenersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ListenersResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + load_balancer_id: str, + name: str, + protocol: LbListenerProtocol, + protocol_port: int, + allowed_cidrs: Optional[SequenceNotStr[str]] | Omit = omit, + connection_limit: int | Omit = omit, + default_pool_id: str | Omit = omit, + insert_x_forwarded: bool | Omit = omit, + secret_id: Literal[""] | Omit = omit, + sni_secret_id: SequenceNotStr[str] | Omit = omit, + timeout_client_data: Optional[int] | Omit = omit, + timeout_member_connect: Optional[int] | Omit = omit, + timeout_member_data: Optional[int] | Omit = omit, + user_list: Iterable[listener_create_params.UserList] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer listener + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: ID of already existent Load Balancer. + + name: Load balancer listener name + + protocol: Load balancer listener protocol + + protocol_port: Protocol port + + allowed_cidrs: Network CIDRs from which service will be accessible + + connection_limit: Limit of the simultaneous connections. If -1 is provided, it is translated to + the default value 100000. + + default_pool_id: ID of already existent Load Balancer Pool to attach listener to. + + insert_x_forwarded: Add headers X-Forwarded-For, X-Forwarded-Port, X-Forwarded-Proto to requests. + Only used with HTTP or `TERMINATED_HTTPS` protocols. + + secret_id: ID of the secret where PKCS12 file is stored for `TERMINATED_HTTPS` or + PROMETHEUS listener + + sni_secret_id: List of secrets IDs containing PKCS12 format certificate/key bundles for + `TERMINATED_HTTPS` or PROMETHEUS listeners + + timeout_client_data: Frontend client inactivity timeout in milliseconds + + timeout_member_connect: Backend member connection timeout in milliseconds. We are recommending to use + `pool.timeout_member_connect` instead. + + timeout_member_data: Backend member inactivity timeout in milliseconds. We are recommending to use + `pool.timeout_member_data` instead. + + user_list: Load balancer listener list of username and encrypted password items + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/lblisteners/{project_id}/{region_id}", + body=maybe_transform( + { + "load_balancer_id": load_balancer_id, + "name": name, + "protocol": protocol, + "protocol_port": protocol_port, + "allowed_cidrs": allowed_cidrs, + "connection_limit": connection_limit, + "default_pool_id": default_pool_id, + "insert_x_forwarded": insert_x_forwarded, + "secret_id": secret_id, + "sni_secret_id": sni_secret_id, + "timeout_client_data": timeout_client_data, + "timeout_member_connect": timeout_member_connect, + "timeout_member_data": timeout_member_data, + "user_list": user_list, + }, + listener_create_params.ListenerCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + listener_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + admin_state_up: bool | Omit = omit, + allowed_cidrs: Optional[SequenceNotStr[str]] | Omit = omit, + connection_limit: int | Omit = omit, + name: str | Omit = omit, + secret_id: Optional[str] | Omit = omit, + sni_secret_id: Optional[SequenceNotStr[str]] | Omit = omit, + timeout_client_data: Optional[int] | Omit = omit, + timeout_member_connect: Optional[int] | Omit = omit, + timeout_member_data: Optional[int] | Omit = omit, + user_list: Optional[Iterable[listener_update_params.UserList]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Update load balancer listener + + Args: + project_id: Project ID + + region_id: Region ID + + listener_id: Listener ID + + admin_state_up: Administrative state of the resource. When set to true, the resource is enabled + and operational. When set to false, the resource is disabled and will not + process traffic. Defaults to true. + + allowed_cidrs: Network CIDRs from which service will be accessible + + connection_limit: Limit of simultaneous connections. If -1 is provided, it is translated to the + default value 100000. + + name: Load balancer listener name + + secret_id: ID of the secret where PKCS12 file is stored for `TERMINATED_HTTPS` or + PROMETHEUS load balancer + + sni_secret_id: List of secret's ID containing PKCS12 format certificate/key bundfles for + `TERMINATED_HTTPS` or PROMETHEUS listeners + + timeout_client_data: Frontend client inactivity timeout in milliseconds + + timeout_member_connect: Backend member connection timeout in milliseconds. We are recommending to use + `pool.timeout_member_connect` instead. + + timeout_member_data: Backend member inactivity timeout in milliseconds. We are recommending to use + `pool.timeout_member_data` instead. + + user_list: Load balancer listener users list + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not listener_id: + raise ValueError(f"Expected a non-empty value for `listener_id` but received {listener_id!r}") + return self._patch( + f"/cloud/v2/lblisteners/{project_id}/{region_id}/{listener_id}", + body=maybe_transform( + { + "admin_state_up": admin_state_up, + "allowed_cidrs": allowed_cidrs, + "connection_limit": connection_limit, + "name": name, + "secret_id": secret_id, + "sni_secret_id": sni_secret_id, + "timeout_client_data": timeout_client_data, + "timeout_member_connect": timeout_member_connect, + "timeout_member_data": timeout_member_data, + "user_list": user_list, + }, + listener_update_params.ListenerUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + load_balancer_id: str | Omit = omit, + show_stats: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerListenerList: + """ + List load balancer listeners + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load Balancer ID + + show_stats: Show stats + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/lblisteners/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "load_balancer_id": load_balancer_id, + "show_stats": show_stats, + }, + listener_list_params.ListenerListParams, + ), + ), + cast_to=LoadBalancerListenerList, + ) + + def delete( + self, + listener_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + delete_default_pool: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete load balancer listener + + Args: + project_id: Project ID + + region_id: Region ID + + listener_id: Listener ID + + delete_default_pool: Delete default pool attached directly to the listener. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not listener_id: + raise ValueError(f"Expected a non-empty value for `listener_id` but received {listener_id!r}") + return self._delete( + f"/cloud/v1/lblisteners/{project_id}/{region_id}/{listener_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + {"delete_default_pool": delete_default_pool}, listener_delete_params.ListenerDeleteParams + ), + ), + cast_to=TaskIDList, + ) + + def get( + self, + listener_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + show_stats: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerListenerDetail: + """ + Get load balancer listener + + Args: + project_id: Project ID + + region_id: Region ID + + listener_id: Listener ID + + show_stats: Show stats + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not listener_id: + raise ValueError(f"Expected a non-empty value for `listener_id` but received {listener_id!r}") + return self._get( + f"/cloud/v1/lblisteners/{project_id}/{region_id}/{listener_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"show_stats": show_stats}, listener_get_params.ListenerGetParams), + ), + cast_to=LoadBalancerListenerDetail, + ) + + +class AsyncListenersResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncListenersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncListenersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncListenersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncListenersResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + load_balancer_id: str, + name: str, + protocol: LbListenerProtocol, + protocol_port: int, + allowed_cidrs: Optional[SequenceNotStr[str]] | Omit = omit, + connection_limit: int | Omit = omit, + default_pool_id: str | Omit = omit, + insert_x_forwarded: bool | Omit = omit, + secret_id: Literal[""] | Omit = omit, + sni_secret_id: SequenceNotStr[str] | Omit = omit, + timeout_client_data: Optional[int] | Omit = omit, + timeout_member_connect: Optional[int] | Omit = omit, + timeout_member_data: Optional[int] | Omit = omit, + user_list: Iterable[listener_create_params.UserList] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer listener + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: ID of already existent Load Balancer. + + name: Load balancer listener name + + protocol: Load balancer listener protocol + + protocol_port: Protocol port + + allowed_cidrs: Network CIDRs from which service will be accessible + + connection_limit: Limit of the simultaneous connections. If -1 is provided, it is translated to + the default value 100000. + + default_pool_id: ID of already existent Load Balancer Pool to attach listener to. + + insert_x_forwarded: Add headers X-Forwarded-For, X-Forwarded-Port, X-Forwarded-Proto to requests. + Only used with HTTP or `TERMINATED_HTTPS` protocols. + + secret_id: ID of the secret where PKCS12 file is stored for `TERMINATED_HTTPS` or + PROMETHEUS listener + + sni_secret_id: List of secrets IDs containing PKCS12 format certificate/key bundles for + `TERMINATED_HTTPS` or PROMETHEUS listeners + + timeout_client_data: Frontend client inactivity timeout in milliseconds + + timeout_member_connect: Backend member connection timeout in milliseconds. We are recommending to use + `pool.timeout_member_connect` instead. + + timeout_member_data: Backend member inactivity timeout in milliseconds. We are recommending to use + `pool.timeout_member_data` instead. + + user_list: Load balancer listener list of username and encrypted password items + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/lblisteners/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "load_balancer_id": load_balancer_id, + "name": name, + "protocol": protocol, + "protocol_port": protocol_port, + "allowed_cidrs": allowed_cidrs, + "connection_limit": connection_limit, + "default_pool_id": default_pool_id, + "insert_x_forwarded": insert_x_forwarded, + "secret_id": secret_id, + "sni_secret_id": sni_secret_id, + "timeout_client_data": timeout_client_data, + "timeout_member_connect": timeout_member_connect, + "timeout_member_data": timeout_member_data, + "user_list": user_list, + }, + listener_create_params.ListenerCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + listener_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + admin_state_up: bool | Omit = omit, + allowed_cidrs: Optional[SequenceNotStr[str]] | Omit = omit, + connection_limit: int | Omit = omit, + name: str | Omit = omit, + secret_id: Optional[str] | Omit = omit, + sni_secret_id: Optional[SequenceNotStr[str]] | Omit = omit, + timeout_client_data: Optional[int] | Omit = omit, + timeout_member_connect: Optional[int] | Omit = omit, + timeout_member_data: Optional[int] | Omit = omit, + user_list: Optional[Iterable[listener_update_params.UserList]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Update load balancer listener + + Args: + project_id: Project ID + + region_id: Region ID + + listener_id: Listener ID + + admin_state_up: Administrative state of the resource. When set to true, the resource is enabled + and operational. When set to false, the resource is disabled and will not + process traffic. Defaults to true. + + allowed_cidrs: Network CIDRs from which service will be accessible + + connection_limit: Limit of simultaneous connections. If -1 is provided, it is translated to the + default value 100000. + + name: Load balancer listener name + + secret_id: ID of the secret where PKCS12 file is stored for `TERMINATED_HTTPS` or + PROMETHEUS load balancer + + sni_secret_id: List of secret's ID containing PKCS12 format certificate/key bundfles for + `TERMINATED_HTTPS` or PROMETHEUS listeners + + timeout_client_data: Frontend client inactivity timeout in milliseconds + + timeout_member_connect: Backend member connection timeout in milliseconds. We are recommending to use + `pool.timeout_member_connect` instead. + + timeout_member_data: Backend member inactivity timeout in milliseconds. We are recommending to use + `pool.timeout_member_data` instead. + + user_list: Load balancer listener users list + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not listener_id: + raise ValueError(f"Expected a non-empty value for `listener_id` but received {listener_id!r}") + return await self._patch( + f"/cloud/v2/lblisteners/{project_id}/{region_id}/{listener_id}", + body=await async_maybe_transform( + { + "admin_state_up": admin_state_up, + "allowed_cidrs": allowed_cidrs, + "connection_limit": connection_limit, + "name": name, + "secret_id": secret_id, + "sni_secret_id": sni_secret_id, + "timeout_client_data": timeout_client_data, + "timeout_member_connect": timeout_member_connect, + "timeout_member_data": timeout_member_data, + "user_list": user_list, + }, + listener_update_params.ListenerUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + load_balancer_id: str | Omit = omit, + show_stats: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerListenerList: + """ + List load balancer listeners + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load Balancer ID + + show_stats: Show stats + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/lblisteners/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "load_balancer_id": load_balancer_id, + "show_stats": show_stats, + }, + listener_list_params.ListenerListParams, + ), + ), + cast_to=LoadBalancerListenerList, + ) + + async def delete( + self, + listener_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + delete_default_pool: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete load balancer listener + + Args: + project_id: Project ID + + region_id: Region ID + + listener_id: Listener ID + + delete_default_pool: Delete default pool attached directly to the listener. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not listener_id: + raise ValueError(f"Expected a non-empty value for `listener_id` but received {listener_id!r}") + return await self._delete( + f"/cloud/v1/lblisteners/{project_id}/{region_id}/{listener_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"delete_default_pool": delete_default_pool}, listener_delete_params.ListenerDeleteParams + ), + ), + cast_to=TaskIDList, + ) + + async def get( + self, + listener_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + show_stats: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerListenerDetail: + """ + Get load balancer listener + + Args: + project_id: Project ID + + region_id: Region ID + + listener_id: Listener ID + + show_stats: Show stats + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not listener_id: + raise ValueError(f"Expected a non-empty value for `listener_id` but received {listener_id!r}") + return await self._get( + f"/cloud/v1/lblisteners/{project_id}/{region_id}/{listener_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"show_stats": show_stats}, listener_get_params.ListenerGetParams), + ), + cast_to=LoadBalancerListenerDetail, + ) + + +class ListenersResourceWithRawResponse: + def __init__(self, listeners: ListenersResource) -> None: + self._listeners = listeners + + self.create = to_raw_response_wrapper( + listeners.create, + ) + self.update = to_raw_response_wrapper( + listeners.update, + ) + self.list = to_raw_response_wrapper( + listeners.list, + ) + self.delete = to_raw_response_wrapper( + listeners.delete, + ) + self.get = to_raw_response_wrapper( + listeners.get, + ) + + +class AsyncListenersResourceWithRawResponse: + def __init__(self, listeners: AsyncListenersResource) -> None: + self._listeners = listeners + + self.create = async_to_raw_response_wrapper( + listeners.create, + ) + self.update = async_to_raw_response_wrapper( + listeners.update, + ) + self.list = async_to_raw_response_wrapper( + listeners.list, + ) + self.delete = async_to_raw_response_wrapper( + listeners.delete, + ) + self.get = async_to_raw_response_wrapper( + listeners.get, + ) + + +class ListenersResourceWithStreamingResponse: + def __init__(self, listeners: ListenersResource) -> None: + self._listeners = listeners + + self.create = to_streamed_response_wrapper( + listeners.create, + ) + self.update = to_streamed_response_wrapper( + listeners.update, + ) + self.list = to_streamed_response_wrapper( + listeners.list, + ) + self.delete = to_streamed_response_wrapper( + listeners.delete, + ) + self.get = to_streamed_response_wrapper( + listeners.get, + ) + + +class AsyncListenersResourceWithStreamingResponse: + def __init__(self, listeners: AsyncListenersResource) -> None: + self._listeners = listeners + + self.create = async_to_streamed_response_wrapper( + listeners.create, + ) + self.update = async_to_streamed_response_wrapper( + listeners.update, + ) + self.list = async_to_streamed_response_wrapper( + listeners.list, + ) + self.delete = async_to_streamed_response_wrapper( + listeners.delete, + ) + self.get = async_to_streamed_response_wrapper( + listeners.get, + ) diff --git a/src/gcore/resources/cloud/load_balancers/load_balancers.py b/src/gcore/resources/cloud/load_balancers/load_balancers.py new file mode 100644 index 00000000..5e59a265 --- /dev/null +++ b/src/gcore/resources/cloud/load_balancers/load_balancers.py @@ -0,0 +1,1417 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import typing_extensions +from typing import Iterable, Optional +from typing_extensions import Literal + +import httpx + +from .flavors import ( + FlavorsResource, + AsyncFlavorsResource, + FlavorsResourceWithRawResponse, + AsyncFlavorsResourceWithRawResponse, + FlavorsResourceWithStreamingResponse, + AsyncFlavorsResourceWithStreamingResponse, +) +from .metrics import ( + MetricsResource, + AsyncMetricsResource, + MetricsResourceWithRawResponse, + AsyncMetricsResourceWithRawResponse, + MetricsResourceWithStreamingResponse, + AsyncMetricsResourceWithStreamingResponse, +) +from .statuses import ( + StatusesResource, + AsyncStatusesResource, + StatusesResourceWithRawResponse, + AsyncStatusesResourceWithRawResponse, + StatusesResourceWithStreamingResponse, + AsyncStatusesResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from .listeners import ( + ListenersResource, + AsyncListenersResource, + ListenersResourceWithRawResponse, + AsyncListenersResourceWithRawResponse, + ListenersResourceWithStreamingResponse, + AsyncListenersResourceWithStreamingResponse, +) +from ...._compat import cached_property +from .pools.pools import ( + PoolsResource, + AsyncPoolsResource, + PoolsResourceWithRawResponse, + AsyncPoolsResourceWithRawResponse, + PoolsResourceWithStreamingResponse, + AsyncPoolsResourceWithStreamingResponse, +) +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ....types.cloud import ( + InterfaceIPFamily, + LoadBalancerMemberConnectivity, + load_balancer_get_params, + load_balancer_list_params, + load_balancer_create_params, + load_balancer_resize_params, + load_balancer_update_params, + load_balancer_failover_params, +) +from ...._base_client import AsyncPaginator, make_request_options +from .l7_policies.l7_policies import ( + L7PoliciesResource, + AsyncL7PoliciesResource, + L7PoliciesResourceWithRawResponse, + AsyncL7PoliciesResourceWithRawResponse, + L7PoliciesResourceWithStreamingResponse, + AsyncL7PoliciesResourceWithStreamingResponse, +) +from ....types.cloud.task_id_list import TaskIDList +from ....types.cloud.load_balancer import LoadBalancer +from ....types.cloud.interface_ip_family import InterfaceIPFamily +from ....types.cloud.tag_update_map_param import TagUpdateMapParam +from ....types.cloud.load_balancer_member_connectivity import LoadBalancerMemberConnectivity + +__all__ = ["LoadBalancersResource", "AsyncLoadBalancersResource"] + + +class LoadBalancersResource(SyncAPIResource): + @cached_property + def l7_policies(self) -> L7PoliciesResource: + return L7PoliciesResource(self._client) + + @cached_property + def flavors(self) -> FlavorsResource: + return FlavorsResource(self._client) + + @cached_property + def listeners(self) -> ListenersResource: + return ListenersResource(self._client) + + @cached_property + def pools(self) -> PoolsResource: + return PoolsResource(self._client) + + @cached_property + def metrics(self) -> MetricsResource: + return MetricsResource(self._client) + + @cached_property + def statuses(self) -> StatusesResource: + return StatusesResource(self._client) + + @cached_property + def with_raw_response(self) -> LoadBalancersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return LoadBalancersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> LoadBalancersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return LoadBalancersResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor: str | Omit = omit, + floating_ip: load_balancer_create_params.FloatingIP | Omit = omit, + listeners: Iterable[load_balancer_create_params.Listener] | Omit = omit, + logging: load_balancer_create_params.Logging | Omit = omit, + name: str | Omit = omit, + name_template: str | Omit = omit, + preferred_connectivity: LoadBalancerMemberConnectivity | Omit = omit, + tags: object | Omit = omit, + vip_ip_family: InterfaceIPFamily | Omit = omit, + vip_network_id: str | Omit = omit, + vip_port_id: str | Omit = omit, + vip_subnet_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer + + Args: + project_id: Project ID + + region_id: Region ID + + flavor: Load balancer flavor name + + floating_ip: Floating IP configuration for assignment + + listeners: Load balancer listeners. Maximum 50 per LB (excluding Prometheus endpoint + listener). + + logging: Logging configuration + + name: Load balancer name. Either `name` or `name_template` should be specified. + + name_template: Load balancer name which will be changed by template. Either `name` or + `name_template` should be specified. + + preferred_connectivity: Preferred option to establish connectivity between load balancer and its pools + members. L2 provides best performance, L3 provides less IPs usage. It is taking + effect only if `instance_id` + `ip_address` is provided, not `subnet_id` + + `ip_address`, because we're considering this as intentional `subnet_id` + specification. + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + vip_ip_family: IP family for load balancer subnet auto-selection if `vip_network_id` is + specified + + vip_network_id: Network ID for load balancer. If not specified, default external network will be + used. Mutually exclusive with `vip_port_id` + + vip_port_id: Existing Reserved Fixed IP port ID for load balancer. Mutually exclusive with + `vip_network_id` + + vip_subnet_id: Subnet ID for load balancer. If not specified, any subnet from `vip_network_id` + will be selected. Ignored when `vip_network_id` is not specified. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}", + body=maybe_transform( + { + "flavor": flavor, + "floating_ip": floating_ip, + "listeners": listeners, + "logging": logging, + "name": name, + "name_template": name_template, + "preferred_connectivity": preferred_connectivity, + "tags": tags, + "vip_ip_family": vip_ip_family, + "vip_network_id": vip_network_id, + "vip_port_id": vip_port_id, + "vip_subnet_id": vip_subnet_id, + }, + load_balancer_create_params.LoadBalancerCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + @typing_extensions.deprecated("deprecated") + def update( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + logging: load_balancer_update_params.Logging | Omit = omit, + name: str | Omit = omit, + preferred_connectivity: LoadBalancerMemberConnectivity | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancer: + """ + Rename load balancer, activate/deactivate logging, update preferred connectivity + type and/or modify load balancer tags. The request will only process the fields + that are provided in the request body. Any fields that are not included will + remain unchanged. + + Please use PATCH `/v2/loadbalancers/{project_id}/{region_id}/{load_balancer_id}` + instead + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + logging: Logging configuration + + name: Name. + + preferred_connectivity: Preferred option to establish connectivity between load balancer and its pools + members + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return self._patch( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}", + body=maybe_transform( + { + "logging": logging, + "name": name, + "preferred_connectivity": preferred_connectivity, + "tags": tags, + }, + load_balancer_update_params.LoadBalancerUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancer, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + assigned_floating: bool | Omit = omit, + limit: int | Omit = omit, + logging_enabled: bool | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal[ + "created_at.asc", + "created_at.desc", + "flavor.asc", + "flavor.desc", + "name.asc", + "name.desc", + "operating_status.asc", + "operating_status.desc", + "provisioning_status.asc", + "provisioning_status.desc", + "updated_at.asc", + "updated_at.desc", + "vip_address.asc", + "vip_address.desc", + "vip_ip_family.asc", + "vip_ip_family.desc", + ] + | Omit = omit, + show_stats: bool | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + with_ddos: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[LoadBalancer]: + """ + List load balancers + + Args: + project_id: Project ID + + region_id: Region ID + + assigned_floating: With or without assigned floating IP + + limit: Limit of items on a single page + + logging_enabled: With or without logging enabled + + name: Filter by name + + offset: Offset in results list + + order_by: Order by field and direction. + + show_stats: Show statistics + + tag_key: Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2 + + tag_key_value: Optional. Filter by tag key-value pairs. + + with_ddos: Show Advanced DDoS protection profile, if exists + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}", + page=SyncOffsetPage[LoadBalancer], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "assigned_floating": assigned_floating, + "limit": limit, + "logging_enabled": logging_enabled, + "name": name, + "offset": offset, + "order_by": order_by, + "show_stats": show_stats, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + "with_ddos": with_ddos, + }, + load_balancer_list_params.LoadBalancerListParams, + ), + ), + model=LoadBalancer, + ) + + def delete( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete load balancer + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return self._delete( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def failover( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + force: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Failover load balancer + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + force: Validate current load balancer status before failover or not. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return self._post( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}/failover", + body=maybe_transform({"force": force}, load_balancer_failover_params.LoadBalancerFailoverParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + show_stats: bool | Omit = omit, + with_ddos: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancer: + """ + Get load balancer + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + show_stats: Show statistics + + with_ddos: Show Advanced DDoS protection profile, if exists + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return self._get( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "show_stats": show_stats, + "with_ddos": with_ddos, + }, + load_balancer_get_params.LoadBalancerGetParams, + ), + ), + cast_to=LoadBalancer, + ) + + def resize( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Resize load balancer + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + flavor: Name of the desired flavor to resize to. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return self._post( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}/resize", + body=maybe_transform({"flavor": flavor}, load_balancer_resize_params.LoadBalancerResizeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncLoadBalancersResource(AsyncAPIResource): + @cached_property + def l7_policies(self) -> AsyncL7PoliciesResource: + return AsyncL7PoliciesResource(self._client) + + @cached_property + def flavors(self) -> AsyncFlavorsResource: + return AsyncFlavorsResource(self._client) + + @cached_property + def listeners(self) -> AsyncListenersResource: + return AsyncListenersResource(self._client) + + @cached_property + def pools(self) -> AsyncPoolsResource: + return AsyncPoolsResource(self._client) + + @cached_property + def metrics(self) -> AsyncMetricsResource: + return AsyncMetricsResource(self._client) + + @cached_property + def statuses(self) -> AsyncStatusesResource: + return AsyncStatusesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncLoadBalancersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncLoadBalancersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncLoadBalancersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncLoadBalancersResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor: str | Omit = omit, + floating_ip: load_balancer_create_params.FloatingIP | Omit = omit, + listeners: Iterable[load_balancer_create_params.Listener] | Omit = omit, + logging: load_balancer_create_params.Logging | Omit = omit, + name: str | Omit = omit, + name_template: str | Omit = omit, + preferred_connectivity: LoadBalancerMemberConnectivity | Omit = omit, + tags: object | Omit = omit, + vip_ip_family: InterfaceIPFamily | Omit = omit, + vip_network_id: str | Omit = omit, + vip_port_id: str | Omit = omit, + vip_subnet_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer + + Args: + project_id: Project ID + + region_id: Region ID + + flavor: Load balancer flavor name + + floating_ip: Floating IP configuration for assignment + + listeners: Load balancer listeners. Maximum 50 per LB (excluding Prometheus endpoint + listener). + + logging: Logging configuration + + name: Load balancer name. Either `name` or `name_template` should be specified. + + name_template: Load balancer name which will be changed by template. Either `name` or + `name_template` should be specified. + + preferred_connectivity: Preferred option to establish connectivity between load balancer and its pools + members. L2 provides best performance, L3 provides less IPs usage. It is taking + effect only if `instance_id` + `ip_address` is provided, not `subnet_id` + + `ip_address`, because we're considering this as intentional `subnet_id` + specification. + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + vip_ip_family: IP family for load balancer subnet auto-selection if `vip_network_id` is + specified + + vip_network_id: Network ID for load balancer. If not specified, default external network will be + used. Mutually exclusive with `vip_port_id` + + vip_port_id: Existing Reserved Fixed IP port ID for load balancer. Mutually exclusive with + `vip_network_id` + + vip_subnet_id: Subnet ID for load balancer. If not specified, any subnet from `vip_network_id` + will be selected. Ignored when `vip_network_id` is not specified. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "flavor": flavor, + "floating_ip": floating_ip, + "listeners": listeners, + "logging": logging, + "name": name, + "name_template": name_template, + "preferred_connectivity": preferred_connectivity, + "tags": tags, + "vip_ip_family": vip_ip_family, + "vip_network_id": vip_network_id, + "vip_port_id": vip_port_id, + "vip_subnet_id": vip_subnet_id, + }, + load_balancer_create_params.LoadBalancerCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + @typing_extensions.deprecated("deprecated") + async def update( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + logging: load_balancer_update_params.Logging | Omit = omit, + name: str | Omit = omit, + preferred_connectivity: LoadBalancerMemberConnectivity | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancer: + """ + Rename load balancer, activate/deactivate logging, update preferred connectivity + type and/or modify load balancer tags. The request will only process the fields + that are provided in the request body. Any fields that are not included will + remain unchanged. + + Please use PATCH `/v2/loadbalancers/{project_id}/{region_id}/{load_balancer_id}` + instead + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + logging: Logging configuration + + name: Name. + + preferred_connectivity: Preferred option to establish connectivity between load balancer and its pools + members + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return await self._patch( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}", + body=await async_maybe_transform( + { + "logging": logging, + "name": name, + "preferred_connectivity": preferred_connectivity, + "tags": tags, + }, + load_balancer_update_params.LoadBalancerUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancer, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + assigned_floating: bool | Omit = omit, + limit: int | Omit = omit, + logging_enabled: bool | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal[ + "created_at.asc", + "created_at.desc", + "flavor.asc", + "flavor.desc", + "name.asc", + "name.desc", + "operating_status.asc", + "operating_status.desc", + "provisioning_status.asc", + "provisioning_status.desc", + "updated_at.asc", + "updated_at.desc", + "vip_address.asc", + "vip_address.desc", + "vip_ip_family.asc", + "vip_ip_family.desc", + ] + | Omit = omit, + show_stats: bool | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + with_ddos: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[LoadBalancer, AsyncOffsetPage[LoadBalancer]]: + """ + List load balancers + + Args: + project_id: Project ID + + region_id: Region ID + + assigned_floating: With or without assigned floating IP + + limit: Limit of items on a single page + + logging_enabled: With or without logging enabled + + name: Filter by name + + offset: Offset in results list + + order_by: Order by field and direction. + + show_stats: Show statistics + + tag_key: Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2 + + tag_key_value: Optional. Filter by tag key-value pairs. + + with_ddos: Show Advanced DDoS protection profile, if exists + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}", + page=AsyncOffsetPage[LoadBalancer], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "assigned_floating": assigned_floating, + "limit": limit, + "logging_enabled": logging_enabled, + "name": name, + "offset": offset, + "order_by": order_by, + "show_stats": show_stats, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + "with_ddos": with_ddos, + }, + load_balancer_list_params.LoadBalancerListParams, + ), + ), + model=LoadBalancer, + ) + + async def delete( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete load balancer + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return await self._delete( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def failover( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + force: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Failover load balancer + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + force: Validate current load balancer status before failover or not. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return await self._post( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}/failover", + body=await async_maybe_transform( + {"force": force}, load_balancer_failover_params.LoadBalancerFailoverParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + show_stats: bool | Omit = omit, + with_ddos: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancer: + """ + Get load balancer + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + show_stats: Show statistics + + with_ddos: Show Advanced DDoS protection profile, if exists + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return await self._get( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "show_stats": show_stats, + "with_ddos": with_ddos, + }, + load_balancer_get_params.LoadBalancerGetParams, + ), + ), + cast_to=LoadBalancer, + ) + + async def resize( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + flavor: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Resize load balancer + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + flavor: Name of the desired flavor to resize to. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return await self._post( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}/resize", + body=await async_maybe_transform({"flavor": flavor}, load_balancer_resize_params.LoadBalancerResizeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class LoadBalancersResourceWithRawResponse: + def __init__(self, load_balancers: LoadBalancersResource) -> None: + self._load_balancers = load_balancers + + self.create = to_raw_response_wrapper( + load_balancers.create, + ) + self.update = ( # pyright: ignore[reportDeprecated] + to_raw_response_wrapper( + load_balancers.update, # pyright: ignore[reportDeprecated], + ) + ) + self.list = to_raw_response_wrapper( + load_balancers.list, + ) + self.delete = to_raw_response_wrapper( + load_balancers.delete, + ) + self.failover = to_raw_response_wrapper( + load_balancers.failover, + ) + self.get = to_raw_response_wrapper( + load_balancers.get, + ) + self.resize = to_raw_response_wrapper( + load_balancers.resize, + ) + + @cached_property + def l7_policies(self) -> L7PoliciesResourceWithRawResponse: + return L7PoliciesResourceWithRawResponse(self._load_balancers.l7_policies) + + @cached_property + def flavors(self) -> FlavorsResourceWithRawResponse: + return FlavorsResourceWithRawResponse(self._load_balancers.flavors) + + @cached_property + def listeners(self) -> ListenersResourceWithRawResponse: + return ListenersResourceWithRawResponse(self._load_balancers.listeners) + + @cached_property + def pools(self) -> PoolsResourceWithRawResponse: + return PoolsResourceWithRawResponse(self._load_balancers.pools) + + @cached_property + def metrics(self) -> MetricsResourceWithRawResponse: + return MetricsResourceWithRawResponse(self._load_balancers.metrics) + + @cached_property + def statuses(self) -> StatusesResourceWithRawResponse: + return StatusesResourceWithRawResponse(self._load_balancers.statuses) + + +class AsyncLoadBalancersResourceWithRawResponse: + def __init__(self, load_balancers: AsyncLoadBalancersResource) -> None: + self._load_balancers = load_balancers + + self.create = async_to_raw_response_wrapper( + load_balancers.create, + ) + self.update = ( # pyright: ignore[reportDeprecated] + async_to_raw_response_wrapper( + load_balancers.update, # pyright: ignore[reportDeprecated], + ) + ) + self.list = async_to_raw_response_wrapper( + load_balancers.list, + ) + self.delete = async_to_raw_response_wrapper( + load_balancers.delete, + ) + self.failover = async_to_raw_response_wrapper( + load_balancers.failover, + ) + self.get = async_to_raw_response_wrapper( + load_balancers.get, + ) + self.resize = async_to_raw_response_wrapper( + load_balancers.resize, + ) + + @cached_property + def l7_policies(self) -> AsyncL7PoliciesResourceWithRawResponse: + return AsyncL7PoliciesResourceWithRawResponse(self._load_balancers.l7_policies) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithRawResponse: + return AsyncFlavorsResourceWithRawResponse(self._load_balancers.flavors) + + @cached_property + def listeners(self) -> AsyncListenersResourceWithRawResponse: + return AsyncListenersResourceWithRawResponse(self._load_balancers.listeners) + + @cached_property + def pools(self) -> AsyncPoolsResourceWithRawResponse: + return AsyncPoolsResourceWithRawResponse(self._load_balancers.pools) + + @cached_property + def metrics(self) -> AsyncMetricsResourceWithRawResponse: + return AsyncMetricsResourceWithRawResponse(self._load_balancers.metrics) + + @cached_property + def statuses(self) -> AsyncStatusesResourceWithRawResponse: + return AsyncStatusesResourceWithRawResponse(self._load_balancers.statuses) + + +class LoadBalancersResourceWithStreamingResponse: + def __init__(self, load_balancers: LoadBalancersResource) -> None: + self._load_balancers = load_balancers + + self.create = to_streamed_response_wrapper( + load_balancers.create, + ) + self.update = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + load_balancers.update, # pyright: ignore[reportDeprecated], + ) + ) + self.list = to_streamed_response_wrapper( + load_balancers.list, + ) + self.delete = to_streamed_response_wrapper( + load_balancers.delete, + ) + self.failover = to_streamed_response_wrapper( + load_balancers.failover, + ) + self.get = to_streamed_response_wrapper( + load_balancers.get, + ) + self.resize = to_streamed_response_wrapper( + load_balancers.resize, + ) + + @cached_property + def l7_policies(self) -> L7PoliciesResourceWithStreamingResponse: + return L7PoliciesResourceWithStreamingResponse(self._load_balancers.l7_policies) + + @cached_property + def flavors(self) -> FlavorsResourceWithStreamingResponse: + return FlavorsResourceWithStreamingResponse(self._load_balancers.flavors) + + @cached_property + def listeners(self) -> ListenersResourceWithStreamingResponse: + return ListenersResourceWithStreamingResponse(self._load_balancers.listeners) + + @cached_property + def pools(self) -> PoolsResourceWithStreamingResponse: + return PoolsResourceWithStreamingResponse(self._load_balancers.pools) + + @cached_property + def metrics(self) -> MetricsResourceWithStreamingResponse: + return MetricsResourceWithStreamingResponse(self._load_balancers.metrics) + + @cached_property + def statuses(self) -> StatusesResourceWithStreamingResponse: + return StatusesResourceWithStreamingResponse(self._load_balancers.statuses) + + +class AsyncLoadBalancersResourceWithStreamingResponse: + def __init__(self, load_balancers: AsyncLoadBalancersResource) -> None: + self._load_balancers = load_balancers + + self.create = async_to_streamed_response_wrapper( + load_balancers.create, + ) + self.update = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + load_balancers.update, # pyright: ignore[reportDeprecated], + ) + ) + self.list = async_to_streamed_response_wrapper( + load_balancers.list, + ) + self.delete = async_to_streamed_response_wrapper( + load_balancers.delete, + ) + self.failover = async_to_streamed_response_wrapper( + load_balancers.failover, + ) + self.get = async_to_streamed_response_wrapper( + load_balancers.get, + ) + self.resize = async_to_streamed_response_wrapper( + load_balancers.resize, + ) + + @cached_property + def l7_policies(self) -> AsyncL7PoliciesResourceWithStreamingResponse: + return AsyncL7PoliciesResourceWithStreamingResponse(self._load_balancers.l7_policies) + + @cached_property + def flavors(self) -> AsyncFlavorsResourceWithStreamingResponse: + return AsyncFlavorsResourceWithStreamingResponse(self._load_balancers.flavors) + + @cached_property + def listeners(self) -> AsyncListenersResourceWithStreamingResponse: + return AsyncListenersResourceWithStreamingResponse(self._load_balancers.listeners) + + @cached_property + def pools(self) -> AsyncPoolsResourceWithStreamingResponse: + return AsyncPoolsResourceWithStreamingResponse(self._load_balancers.pools) + + @cached_property + def metrics(self) -> AsyncMetricsResourceWithStreamingResponse: + return AsyncMetricsResourceWithStreamingResponse(self._load_balancers.metrics) + + @cached_property + def statuses(self) -> AsyncStatusesResourceWithStreamingResponse: + return AsyncStatusesResourceWithStreamingResponse(self._load_balancers.statuses) diff --git a/src/gcore/resources/cloud/load_balancers/metrics.py b/src/gcore/resources/cloud/load_balancers/metrics.py new file mode 100644 index 00000000..a66adc6e --- /dev/null +++ b/src/gcore/resources/cloud/load_balancers/metrics.py @@ -0,0 +1,217 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....types.cloud import InstanceMetricsTimeUnit +from ...._base_client import make_request_options +from ....types.cloud.load_balancers import metric_list_params +from ....types.cloud.instance_metrics_time_unit import InstanceMetricsTimeUnit +from ....types.cloud.load_balancer_metrics_list import LoadBalancerMetricsList + +__all__ = ["MetricsResource", "AsyncMetricsResource"] + + +class MetricsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> MetricsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return MetricsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MetricsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return MetricsResourceWithStreamingResponse(self) + + def list( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + time_interval: int, + time_unit: InstanceMetricsTimeUnit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerMetricsList: + """ + Get load balancer metrics, including cpu, memory and network + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + time_interval: Time interval + + time_unit: Time interval unit + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return self._post( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}/metrics", + body=maybe_transform( + { + "time_interval": time_interval, + "time_unit": time_unit, + }, + metric_list_params.MetricListParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerMetricsList, + ) + + +class AsyncMetricsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncMetricsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncMetricsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMetricsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncMetricsResourceWithStreamingResponse(self) + + async def list( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + time_interval: int, + time_unit: InstanceMetricsTimeUnit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerMetricsList: + """ + Get load balancer metrics, including cpu, memory and network + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + time_interval: Time interval + + time_unit: Time interval unit + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return await self._post( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}/metrics", + body=await async_maybe_transform( + { + "time_interval": time_interval, + "time_unit": time_unit, + }, + metric_list_params.MetricListParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerMetricsList, + ) + + +class MetricsResourceWithRawResponse: + def __init__(self, metrics: MetricsResource) -> None: + self._metrics = metrics + + self.list = to_raw_response_wrapper( + metrics.list, + ) + + +class AsyncMetricsResourceWithRawResponse: + def __init__(self, metrics: AsyncMetricsResource) -> None: + self._metrics = metrics + + self.list = async_to_raw_response_wrapper( + metrics.list, + ) + + +class MetricsResourceWithStreamingResponse: + def __init__(self, metrics: MetricsResource) -> None: + self._metrics = metrics + + self.list = to_streamed_response_wrapper( + metrics.list, + ) + + +class AsyncMetricsResourceWithStreamingResponse: + def __init__(self, metrics: AsyncMetricsResource) -> None: + self._metrics = metrics + + self.list = async_to_streamed_response_wrapper( + metrics.list, + ) diff --git a/src/gcore/resources/cloud/load_balancers/pools/__init__.py b/src/gcore/resources/cloud/load_balancers/pools/__init__.py new file mode 100644 index 00000000..c9c02f6d --- /dev/null +++ b/src/gcore/resources/cloud/load_balancers/pools/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .pools import ( + PoolsResource, + AsyncPoolsResource, + PoolsResourceWithRawResponse, + AsyncPoolsResourceWithRawResponse, + PoolsResourceWithStreamingResponse, + AsyncPoolsResourceWithStreamingResponse, +) +from .members import ( + MembersResource, + AsyncMembersResource, + MembersResourceWithRawResponse, + AsyncMembersResourceWithRawResponse, + MembersResourceWithStreamingResponse, + AsyncMembersResourceWithStreamingResponse, +) +from .health_monitors import ( + HealthMonitorsResource, + AsyncHealthMonitorsResource, + HealthMonitorsResourceWithRawResponse, + AsyncHealthMonitorsResourceWithRawResponse, + HealthMonitorsResourceWithStreamingResponse, + AsyncHealthMonitorsResourceWithStreamingResponse, +) + +__all__ = [ + "HealthMonitorsResource", + "AsyncHealthMonitorsResource", + "HealthMonitorsResourceWithRawResponse", + "AsyncHealthMonitorsResourceWithRawResponse", + "HealthMonitorsResourceWithStreamingResponse", + "AsyncHealthMonitorsResourceWithStreamingResponse", + "MembersResource", + "AsyncMembersResource", + "MembersResourceWithRawResponse", + "AsyncMembersResourceWithRawResponse", + "MembersResourceWithStreamingResponse", + "AsyncMembersResourceWithStreamingResponse", + "PoolsResource", + "AsyncPoolsResource", + "PoolsResourceWithRawResponse", + "AsyncPoolsResourceWithRawResponse", + "PoolsResourceWithStreamingResponse", + "AsyncPoolsResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/load_balancers/pools/health_monitors.py b/src/gcore/resources/cloud/load_balancers/pools/health_monitors.py new file mode 100644 index 00000000..33f56bcc --- /dev/null +++ b/src/gcore/resources/cloud/load_balancers/pools/health_monitors.py @@ -0,0 +1,404 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ....._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .....types.cloud import HTTPMethod, LbHealthMonitorType +from ....._base_client import make_request_options +from .....types.cloud.http_method import HTTPMethod +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.load_balancers.pools import health_monitor_create_params +from .....types.cloud.lb_health_monitor_type import LbHealthMonitorType + +__all__ = ["HealthMonitorsResource", "AsyncHealthMonitorsResource"] + + +class HealthMonitorsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> HealthMonitorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return HealthMonitorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> HealthMonitorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return HealthMonitorsResourceWithStreamingResponse(self) + + def create( + self, + pool_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + delay: int, + max_retries: int, + api_timeout: int, + type: LbHealthMonitorType, + admin_state_up: bool | Omit = omit, + expected_codes: Optional[str] | Omit = omit, + http_method: Optional[HTTPMethod] | Omit = omit, + max_retries_down: int | Omit = omit, + url_path: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Creates a health monitor for a load balancer pool to automatically check the + health status of pool members. The health monitor performs periodic checks on + pool members and removes unhealthy members from rotation, ensuring only healthy + servers receive traffic. + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + delay: The time, in seconds, between sending probes to members + + max_retries: Number of successes before the member is switched to ONLINE state + + api_timeout: The maximum time to connect. Must be less than the delay value + + type: Health monitor type. Once health monitor is created, cannot be changed. + + admin_state_up: Administrative state of the resource. When set to true, the resource is enabled + and operational. When set to false, the resource is disabled and will not + process traffic. Defaults to true. + + expected_codes: Expected HTTP response codes. Can be a single code or a range of codes. Can only + be used together with `HTTP` or `HTTPS` health monitor type. For example, + 200,202,300-302,401,403,404,500-504. If not specified, the default is 200. + + http_method: HTTP method. Can only be used together with `HTTP` or `HTTPS` health monitor + type. + + max_retries_down: Number of failures before the member is switched to ERROR state. + + url_path: URL Path. Defaults to '/'. Can only be used together with `HTTP` or `HTTPS` + health monitor type. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + return self._post( + f"/cloud/v1/lbpools/{project_id}/{region_id}/{pool_id}/healthmonitor", + body=maybe_transform( + { + "delay": delay, + "max_retries": max_retries, + "api_timeout": api_timeout, + "type": type, + "admin_state_up": admin_state_up, + "expected_codes": expected_codes, + "http_method": http_method, + "max_retries_down": max_retries_down, + "url_path": url_path, + }, + health_monitor_create_params.HealthMonitorCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def delete( + self, + pool_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Removes the health monitor from a load balancer pool. + + After deletion, the pool + will no longer perform automatic health checks on its members, and all members + will remain in rotation regardless of their actual health status. + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v1/lbpools/{project_id}/{region_id}/{pool_id}/healthmonitor", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncHealthMonitorsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncHealthMonitorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncHealthMonitorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncHealthMonitorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncHealthMonitorsResourceWithStreamingResponse(self) + + async def create( + self, + pool_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + delay: int, + max_retries: int, + api_timeout: int, + type: LbHealthMonitorType, + admin_state_up: bool | Omit = omit, + expected_codes: Optional[str] | Omit = omit, + http_method: Optional[HTTPMethod] | Omit = omit, + max_retries_down: int | Omit = omit, + url_path: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Creates a health monitor for a load balancer pool to automatically check the + health status of pool members. The health monitor performs periodic checks on + pool members and removes unhealthy members from rotation, ensuring only healthy + servers receive traffic. + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + delay: The time, in seconds, between sending probes to members + + max_retries: Number of successes before the member is switched to ONLINE state + + api_timeout: The maximum time to connect. Must be less than the delay value + + type: Health monitor type. Once health monitor is created, cannot be changed. + + admin_state_up: Administrative state of the resource. When set to true, the resource is enabled + and operational. When set to false, the resource is disabled and will not + process traffic. Defaults to true. + + expected_codes: Expected HTTP response codes. Can be a single code or a range of codes. Can only + be used together with `HTTP` or `HTTPS` health monitor type. For example, + 200,202,300-302,401,403,404,500-504. If not specified, the default is 200. + + http_method: HTTP method. Can only be used together with `HTTP` or `HTTPS` health monitor + type. + + max_retries_down: Number of failures before the member is switched to ERROR state. + + url_path: URL Path. Defaults to '/'. Can only be used together with `HTTP` or `HTTPS` + health monitor type. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + return await self._post( + f"/cloud/v1/lbpools/{project_id}/{region_id}/{pool_id}/healthmonitor", + body=await async_maybe_transform( + { + "delay": delay, + "max_retries": max_retries, + "api_timeout": api_timeout, + "type": type, + "admin_state_up": admin_state_up, + "expected_codes": expected_codes, + "http_method": http_method, + "max_retries_down": max_retries_down, + "url_path": url_path, + }, + health_monitor_create_params.HealthMonitorCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def delete( + self, + pool_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Removes the health monitor from a load balancer pool. + + After deletion, the pool + will no longer perform automatic health checks on its members, and all members + will remain in rotation regardless of their actual health status. + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v1/lbpools/{project_id}/{region_id}/{pool_id}/healthmonitor", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class HealthMonitorsResourceWithRawResponse: + def __init__(self, health_monitors: HealthMonitorsResource) -> None: + self._health_monitors = health_monitors + + self.create = to_raw_response_wrapper( + health_monitors.create, + ) + self.delete = to_raw_response_wrapper( + health_monitors.delete, + ) + + +class AsyncHealthMonitorsResourceWithRawResponse: + def __init__(self, health_monitors: AsyncHealthMonitorsResource) -> None: + self._health_monitors = health_monitors + + self.create = async_to_raw_response_wrapper( + health_monitors.create, + ) + self.delete = async_to_raw_response_wrapper( + health_monitors.delete, + ) + + +class HealthMonitorsResourceWithStreamingResponse: + def __init__(self, health_monitors: HealthMonitorsResource) -> None: + self._health_monitors = health_monitors + + self.create = to_streamed_response_wrapper( + health_monitors.create, + ) + self.delete = to_streamed_response_wrapper( + health_monitors.delete, + ) + + +class AsyncHealthMonitorsResourceWithStreamingResponse: + def __init__(self, health_monitors: AsyncHealthMonitorsResource) -> None: + self._health_monitors = health_monitors + + self.create = async_to_streamed_response_wrapper( + health_monitors.create, + ) + self.delete = async_to_streamed_response_wrapper( + health_monitors.delete, + ) diff --git a/src/gcore/resources/cloud/load_balancers/pools/members.py b/src/gcore/resources/cloud/load_balancers/pools/members.py new file mode 100644 index 00000000..d28d22ef --- /dev/null +++ b/src/gcore/resources/cloud/load_balancers/pools/members.py @@ -0,0 +1,431 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.load_balancers.pools import member_create_params + +__all__ = ["MembersResource", "AsyncMembersResource"] + + +class MembersResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> MembersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return MembersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MembersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return MembersResourceWithStreamingResponse(self) + + def create( + self, + pool_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + address: str, + protocol_port: int, + admin_state_up: bool | Omit = omit, + backup: bool | Omit = omit, + instance_id: Optional[str] | Omit = omit, + monitor_address: Optional[str] | Omit = omit, + monitor_port: Optional[int] | Omit = omit, + subnet_id: Optional[str] | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer pool member + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + address: Member IP address + + protocol_port: Member IP port + + admin_state_up: Administrative state of the resource. When set to true, the resource is enabled + and operational. When set to false, the resource is disabled and will not + process traffic. Defaults to true. + + backup: Set to true if the member is a backup member, to which traffic will be sent + exclusively when all non-backup members will be unreachable. It allows to + realize ACTIVE-BACKUP load balancing without thinking about VRRP and VIP + configuration. Default is false. + + instance_id: Either `subnet_id` or `instance_id` should be provided + + monitor_address: An alternate IP address used for health monitoring of a backend member. Default + is null which monitors the member address. + + monitor_port: An alternate protocol port used for health monitoring of a backend member. + Default is null which monitors the member `protocol_port`. + + subnet_id: `subnet_id` in which `address` is present. Either `subnet_id` or `instance_id` + should be provided + + weight: Member weight. Valid values are 0 < `weight` <= 256, defaults to 1. Controls + traffic distribution based on the pool's load balancing algorithm: + + - `ROUND_ROBIN`: Distributes connections to each member in turn according to + weights. Higher weight = more turns in the cycle. Example: weights 3 vs 1 = + ~75% vs ~25% of requests. + - `LEAST_CONNECTIONS`: Sends new connections to the member with fewest active + connections, performing round-robin within groups of the same normalized load. + Higher weight = allowed to hold more simultaneous connections before being + considered 'more loaded'. Example: weights 2 vs 1 means 20 vs 10 active + connections is treated as balanced. + - `SOURCE_IP`: Routes clients consistently to the same member by hashing client + source IP; hash result is modulo total weight of running members. Higher + weight = more hash buckets, so more client IPs map to that member. Example: + weights 2 vs 1 = roughly two-thirds of distinct client IPs map to the + higher-weight member. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + return self._post( + f"/cloud/v1/lbpools/{project_id}/{region_id}/{pool_id}/member", + body=maybe_transform( + { + "address": address, + "protocol_port": protocol_port, + "admin_state_up": admin_state_up, + "backup": backup, + "instance_id": instance_id, + "monitor_address": monitor_address, + "monitor_port": monitor_port, + "subnet_id": subnet_id, + "weight": weight, + }, + member_create_params.MemberCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def delete( + self, + member_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + pool_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete load balancer pool member + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + member_id: Member ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + if not member_id: + raise ValueError(f"Expected a non-empty value for `member_id` but received {member_id!r}") + return self._delete( + f"/cloud/v1/lbpools/{project_id}/{region_id}/{pool_id}/member/{member_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncMembersResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncMembersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncMembersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMembersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncMembersResourceWithStreamingResponse(self) + + async def create( + self, + pool_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + address: str, + protocol_port: int, + admin_state_up: bool | Omit = omit, + backup: bool | Omit = omit, + instance_id: Optional[str] | Omit = omit, + monitor_address: Optional[str] | Omit = omit, + monitor_port: Optional[int] | Omit = omit, + subnet_id: Optional[str] | Omit = omit, + weight: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer pool member + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + address: Member IP address + + protocol_port: Member IP port + + admin_state_up: Administrative state of the resource. When set to true, the resource is enabled + and operational. When set to false, the resource is disabled and will not + process traffic. Defaults to true. + + backup: Set to true if the member is a backup member, to which traffic will be sent + exclusively when all non-backup members will be unreachable. It allows to + realize ACTIVE-BACKUP load balancing without thinking about VRRP and VIP + configuration. Default is false. + + instance_id: Either `subnet_id` or `instance_id` should be provided + + monitor_address: An alternate IP address used for health monitoring of a backend member. Default + is null which monitors the member address. + + monitor_port: An alternate protocol port used for health monitoring of a backend member. + Default is null which monitors the member `protocol_port`. + + subnet_id: `subnet_id` in which `address` is present. Either `subnet_id` or `instance_id` + should be provided + + weight: Member weight. Valid values are 0 < `weight` <= 256, defaults to 1. Controls + traffic distribution based on the pool's load balancing algorithm: + + - `ROUND_ROBIN`: Distributes connections to each member in turn according to + weights. Higher weight = more turns in the cycle. Example: weights 3 vs 1 = + ~75% vs ~25% of requests. + - `LEAST_CONNECTIONS`: Sends new connections to the member with fewest active + connections, performing round-robin within groups of the same normalized load. + Higher weight = allowed to hold more simultaneous connections before being + considered 'more loaded'. Example: weights 2 vs 1 means 20 vs 10 active + connections is treated as balanced. + - `SOURCE_IP`: Routes clients consistently to the same member by hashing client + source IP; hash result is modulo total weight of running members. Higher + weight = more hash buckets, so more client IPs map to that member. Example: + weights 2 vs 1 = roughly two-thirds of distinct client IPs map to the + higher-weight member. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + return await self._post( + f"/cloud/v1/lbpools/{project_id}/{region_id}/{pool_id}/member", + body=await async_maybe_transform( + { + "address": address, + "protocol_port": protocol_port, + "admin_state_up": admin_state_up, + "backup": backup, + "instance_id": instance_id, + "monitor_address": monitor_address, + "monitor_port": monitor_port, + "subnet_id": subnet_id, + "weight": weight, + }, + member_create_params.MemberCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def delete( + self, + member_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + pool_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete load balancer pool member + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + member_id: Member ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + if not member_id: + raise ValueError(f"Expected a non-empty value for `member_id` but received {member_id!r}") + return await self._delete( + f"/cloud/v1/lbpools/{project_id}/{region_id}/{pool_id}/member/{member_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class MembersResourceWithRawResponse: + def __init__(self, members: MembersResource) -> None: + self._members = members + + self.create = to_raw_response_wrapper( + members.create, + ) + self.delete = to_raw_response_wrapper( + members.delete, + ) + + +class AsyncMembersResourceWithRawResponse: + def __init__(self, members: AsyncMembersResource) -> None: + self._members = members + + self.create = async_to_raw_response_wrapper( + members.create, + ) + self.delete = async_to_raw_response_wrapper( + members.delete, + ) + + +class MembersResourceWithStreamingResponse: + def __init__(self, members: MembersResource) -> None: + self._members = members + + self.create = to_streamed_response_wrapper( + members.create, + ) + self.delete = to_streamed_response_wrapper( + members.delete, + ) + + +class AsyncMembersResourceWithStreamingResponse: + def __init__(self, members: AsyncMembersResource) -> None: + self._members = members + + self.create = async_to_streamed_response_wrapper( + members.create, + ) + self.delete = async_to_streamed_response_wrapper( + members.delete, + ) diff --git a/src/gcore/resources/cloud/load_balancers/pools/pools.py b/src/gcore/resources/cloud/load_balancers/pools/pools.py new file mode 100644 index 00000000..18af7de2 --- /dev/null +++ b/src/gcore/resources/cloud/load_balancers/pools/pools.py @@ -0,0 +1,968 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional + +import httpx + +from .members import ( + MembersResource, + AsyncMembersResource, + MembersResourceWithRawResponse, + AsyncMembersResourceWithRawResponse, + MembersResourceWithStreamingResponse, + AsyncMembersResourceWithStreamingResponse, +) +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .....types.cloud import LbAlgorithm, LbPoolProtocol +from .health_monitors import ( + HealthMonitorsResource, + AsyncHealthMonitorsResource, + HealthMonitorsResourceWithRawResponse, + AsyncHealthMonitorsResourceWithRawResponse, + HealthMonitorsResourceWithStreamingResponse, + AsyncHealthMonitorsResourceWithStreamingResponse, +) +from ....._base_client import make_request_options +from .....types.cloud.lb_algorithm import LbAlgorithm +from .....types.cloud.task_id_list import TaskIDList +from .....types.cloud.load_balancers import pool_list_params, pool_create_params, pool_update_params +from .....types.cloud.lb_pool_protocol import LbPoolProtocol +from .....types.cloud.load_balancer_pool import LoadBalancerPool +from .....types.cloud.load_balancer_pool_list import LoadBalancerPoolList + +__all__ = ["PoolsResource", "AsyncPoolsResource"] + + +class PoolsResource(SyncAPIResource): + @cached_property + def health_monitors(self) -> HealthMonitorsResource: + return HealthMonitorsResource(self._client) + + @cached_property + def members(self) -> MembersResource: + return MembersResource(self._client) + + @cached_property + def with_raw_response(self) -> PoolsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return PoolsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PoolsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return PoolsResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + lb_algorithm: LbAlgorithm, + name: str, + protocol: LbPoolProtocol, + ca_secret_id: Optional[str] | Omit = omit, + crl_secret_id: Optional[str] | Omit = omit, + healthmonitor: Optional[pool_create_params.Healthmonitor] | Omit = omit, + listener_id: Optional[str] | Omit = omit, + load_balancer_id: Optional[str] | Omit = omit, + members: Iterable[pool_create_params.Member] | Omit = omit, + secret_id: Optional[str] | Omit = omit, + session_persistence: Optional[pool_create_params.SessionPersistence] | Omit = omit, + timeout_client_data: Optional[int] | Omit = omit, + timeout_member_connect: Optional[int] | Omit = omit, + timeout_member_data: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer pool + + Args: + project_id: Project ID + + region_id: Region ID + + lb_algorithm: Load balancer algorithm + + name: Pool name + + protocol: Protocol + + ca_secret_id: Secret ID of CA certificate bundle + + crl_secret_id: Secret ID of CA revocation list file + + healthmonitor: Health monitor details + + listener_id: Listener ID + + load_balancer_id: Loadbalancer ID + + members: Pool members + + secret_id: Secret ID for TLS client authentication to the member servers + + session_persistence: Session persistence details + + timeout_client_data: Frontend client inactivity timeout in milliseconds. We are recommending to use + `listener.timeout_client_data` instead. + + timeout_member_connect: Backend member connection timeout in milliseconds + + timeout_member_data: Backend member inactivity timeout in milliseconds + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/lbpools/{project_id}/{region_id}", + body=maybe_transform( + { + "lb_algorithm": lb_algorithm, + "name": name, + "protocol": protocol, + "ca_secret_id": ca_secret_id, + "crl_secret_id": crl_secret_id, + "healthmonitor": healthmonitor, + "listener_id": listener_id, + "load_balancer_id": load_balancer_id, + "members": members, + "secret_id": secret_id, + "session_persistence": session_persistence, + "timeout_client_data": timeout_client_data, + "timeout_member_connect": timeout_member_connect, + "timeout_member_data": timeout_member_data, + }, + pool_create_params.PoolCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + pool_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + admin_state_up: bool | Omit = omit, + ca_secret_id: Optional[str] | Omit = omit, + crl_secret_id: Optional[str] | Omit = omit, + healthmonitor: Optional[pool_update_params.Healthmonitor] | Omit = omit, + lb_algorithm: LbAlgorithm | Omit = omit, + members: Optional[Iterable[pool_update_params.Member]] | Omit = omit, + name: str | Omit = omit, + protocol: LbPoolProtocol | Omit = omit, + secret_id: Optional[str] | Omit = omit, + session_persistence: Optional[pool_update_params.SessionPersistence] | Omit = omit, + timeout_client_data: Optional[int] | Omit = omit, + timeout_member_connect: Optional[int] | Omit = omit, + timeout_member_data: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Updates the specified load balancer pool with the provided changes. + + **Behavior:** + + - Simple fields (strings, numbers, booleans) will be updated if provided + - Complex objects (nested structures like members, health monitors, etc.) must + be specified completely - partial updates are not supported for these objects + - Undefined fields will remain unchanged + - If no change is detected for a specific field compared to the current pool + state, that field will be skipped + - If no changes are detected at all across all fields, no task will be created + and an empty task list will be returned + + **Examples of complex objects that require full specification:** + + - Pool members: All member properties must be provided when updating members + - Health monitors: Complete health monitor configuration must be specified + - Session persistence: Full session persistence settings must be included + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + admin_state_up: Administrative state of the resource. When set to true, the resource is enabled + and operational. When set to false, the resource is disabled and will not + process traffic. Defaults to true. + + ca_secret_id: Secret ID of CA certificate bundle + + crl_secret_id: Secret ID of CA revocation list file + + healthmonitor: New pool health monitor settings + + lb_algorithm: New load balancer pool algorithm of how to distribute requests + + members: New sequence of load balancer pool members. If members are the same (by + address + port), they will be kept as is without recreation and downtime. + + name: New pool name + + protocol: New communication protocol + + secret_id: Secret ID for TLS client authentication to the member servers + + session_persistence: New session persistence settings + + timeout_client_data: Frontend client inactivity timeout in milliseconds. We are recommending to use + `listener.timeout_client_data` instead. + + timeout_member_connect: Backend member connection timeout in milliseconds + + timeout_member_data: Backend member inactivity timeout in milliseconds + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + return self._patch( + f"/cloud/v2/lbpools/{project_id}/{region_id}/{pool_id}", + body=maybe_transform( + { + "admin_state_up": admin_state_up, + "ca_secret_id": ca_secret_id, + "crl_secret_id": crl_secret_id, + "healthmonitor": healthmonitor, + "lb_algorithm": lb_algorithm, + "members": members, + "name": name, + "protocol": protocol, + "secret_id": secret_id, + "session_persistence": session_persistence, + "timeout_client_data": timeout_client_data, + "timeout_member_connect": timeout_member_connect, + "timeout_member_data": timeout_member_data, + }, + pool_update_params.PoolUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + details: bool | Omit = omit, + listener_id: str | Omit = omit, + load_balancer_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerPoolList: + """ + List load balancer pools + + Args: + project_id: Project ID + + region_id: Region ID + + details: Show members and Health Monitor details + + listener_id: Listener ID + + load_balancer_id: Load Balancer ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/lbpools/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "details": details, + "listener_id": listener_id, + "load_balancer_id": load_balancer_id, + }, + pool_list_params.PoolListParams, + ), + ), + cast_to=LoadBalancerPoolList, + ) + + def delete( + self, + pool_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete load balancer pool + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + return self._delete( + f"/cloud/v1/lbpools/{project_id}/{region_id}/{pool_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + pool_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerPool: + """ + Get load balancer pool + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + return self._get( + f"/cloud/v1/lbpools/{project_id}/{region_id}/{pool_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerPool, + ) + + +class AsyncPoolsResource(AsyncAPIResource): + @cached_property + def health_monitors(self) -> AsyncHealthMonitorsResource: + return AsyncHealthMonitorsResource(self._client) + + @cached_property + def members(self) -> AsyncMembersResource: + return AsyncMembersResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncPoolsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncPoolsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPoolsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncPoolsResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + lb_algorithm: LbAlgorithm, + name: str, + protocol: LbPoolProtocol, + ca_secret_id: Optional[str] | Omit = omit, + crl_secret_id: Optional[str] | Omit = omit, + healthmonitor: Optional[pool_create_params.Healthmonitor] | Omit = omit, + listener_id: Optional[str] | Omit = omit, + load_balancer_id: Optional[str] | Omit = omit, + members: Iterable[pool_create_params.Member] | Omit = omit, + secret_id: Optional[str] | Omit = omit, + session_persistence: Optional[pool_create_params.SessionPersistence] | Omit = omit, + timeout_client_data: Optional[int] | Omit = omit, + timeout_member_connect: Optional[int] | Omit = omit, + timeout_member_data: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create load balancer pool + + Args: + project_id: Project ID + + region_id: Region ID + + lb_algorithm: Load balancer algorithm + + name: Pool name + + protocol: Protocol + + ca_secret_id: Secret ID of CA certificate bundle + + crl_secret_id: Secret ID of CA revocation list file + + healthmonitor: Health monitor details + + listener_id: Listener ID + + load_balancer_id: Loadbalancer ID + + members: Pool members + + secret_id: Secret ID for TLS client authentication to the member servers + + session_persistence: Session persistence details + + timeout_client_data: Frontend client inactivity timeout in milliseconds. We are recommending to use + `listener.timeout_client_data` instead. + + timeout_member_connect: Backend member connection timeout in milliseconds + + timeout_member_data: Backend member inactivity timeout in milliseconds + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/lbpools/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "lb_algorithm": lb_algorithm, + "name": name, + "protocol": protocol, + "ca_secret_id": ca_secret_id, + "crl_secret_id": crl_secret_id, + "healthmonitor": healthmonitor, + "listener_id": listener_id, + "load_balancer_id": load_balancer_id, + "members": members, + "secret_id": secret_id, + "session_persistence": session_persistence, + "timeout_client_data": timeout_client_data, + "timeout_member_connect": timeout_member_connect, + "timeout_member_data": timeout_member_data, + }, + pool_create_params.PoolCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + pool_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + admin_state_up: bool | Omit = omit, + ca_secret_id: Optional[str] | Omit = omit, + crl_secret_id: Optional[str] | Omit = omit, + healthmonitor: Optional[pool_update_params.Healthmonitor] | Omit = omit, + lb_algorithm: LbAlgorithm | Omit = omit, + members: Optional[Iterable[pool_update_params.Member]] | Omit = omit, + name: str | Omit = omit, + protocol: LbPoolProtocol | Omit = omit, + secret_id: Optional[str] | Omit = omit, + session_persistence: Optional[pool_update_params.SessionPersistence] | Omit = omit, + timeout_client_data: Optional[int] | Omit = omit, + timeout_member_connect: Optional[int] | Omit = omit, + timeout_member_data: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Updates the specified load balancer pool with the provided changes. + + **Behavior:** + + - Simple fields (strings, numbers, booleans) will be updated if provided + - Complex objects (nested structures like members, health monitors, etc.) must + be specified completely - partial updates are not supported for these objects + - Undefined fields will remain unchanged + - If no change is detected for a specific field compared to the current pool + state, that field will be skipped + - If no changes are detected at all across all fields, no task will be created + and an empty task list will be returned + + **Examples of complex objects that require full specification:** + + - Pool members: All member properties must be provided when updating members + - Health monitors: Complete health monitor configuration must be specified + - Session persistence: Full session persistence settings must be included + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + admin_state_up: Administrative state of the resource. When set to true, the resource is enabled + and operational. When set to false, the resource is disabled and will not + process traffic. Defaults to true. + + ca_secret_id: Secret ID of CA certificate bundle + + crl_secret_id: Secret ID of CA revocation list file + + healthmonitor: New pool health monitor settings + + lb_algorithm: New load balancer pool algorithm of how to distribute requests + + members: New sequence of load balancer pool members. If members are the same (by + address + port), they will be kept as is without recreation and downtime. + + name: New pool name + + protocol: New communication protocol + + secret_id: Secret ID for TLS client authentication to the member servers + + session_persistence: New session persistence settings + + timeout_client_data: Frontend client inactivity timeout in milliseconds. We are recommending to use + `listener.timeout_client_data` instead. + + timeout_member_connect: Backend member connection timeout in milliseconds + + timeout_member_data: Backend member inactivity timeout in milliseconds + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + return await self._patch( + f"/cloud/v2/lbpools/{project_id}/{region_id}/{pool_id}", + body=await async_maybe_transform( + { + "admin_state_up": admin_state_up, + "ca_secret_id": ca_secret_id, + "crl_secret_id": crl_secret_id, + "healthmonitor": healthmonitor, + "lb_algorithm": lb_algorithm, + "members": members, + "name": name, + "protocol": protocol, + "secret_id": secret_id, + "session_persistence": session_persistence, + "timeout_client_data": timeout_client_data, + "timeout_member_connect": timeout_member_connect, + "timeout_member_data": timeout_member_data, + }, + pool_update_params.PoolUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + details: bool | Omit = omit, + listener_id: str | Omit = omit, + load_balancer_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerPoolList: + """ + List load balancer pools + + Args: + project_id: Project ID + + region_id: Region ID + + details: Show members and Health Monitor details + + listener_id: Listener ID + + load_balancer_id: Load Balancer ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/lbpools/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "details": details, + "listener_id": listener_id, + "load_balancer_id": load_balancer_id, + }, + pool_list_params.PoolListParams, + ), + ), + cast_to=LoadBalancerPoolList, + ) + + async def delete( + self, + pool_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete load balancer pool + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + return await self._delete( + f"/cloud/v1/lbpools/{project_id}/{region_id}/{pool_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + pool_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerPool: + """ + Get load balancer pool + + Args: + project_id: Project ID + + region_id: Region ID + + pool_id: Pool ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not pool_id: + raise ValueError(f"Expected a non-empty value for `pool_id` but received {pool_id!r}") + return await self._get( + f"/cloud/v1/lbpools/{project_id}/{region_id}/{pool_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerPool, + ) + + +class PoolsResourceWithRawResponse: + def __init__(self, pools: PoolsResource) -> None: + self._pools = pools + + self.create = to_raw_response_wrapper( + pools.create, + ) + self.update = to_raw_response_wrapper( + pools.update, + ) + self.list = to_raw_response_wrapper( + pools.list, + ) + self.delete = to_raw_response_wrapper( + pools.delete, + ) + self.get = to_raw_response_wrapper( + pools.get, + ) + + @cached_property + def health_monitors(self) -> HealthMonitorsResourceWithRawResponse: + return HealthMonitorsResourceWithRawResponse(self._pools.health_monitors) + + @cached_property + def members(self) -> MembersResourceWithRawResponse: + return MembersResourceWithRawResponse(self._pools.members) + + +class AsyncPoolsResourceWithRawResponse: + def __init__(self, pools: AsyncPoolsResource) -> None: + self._pools = pools + + self.create = async_to_raw_response_wrapper( + pools.create, + ) + self.update = async_to_raw_response_wrapper( + pools.update, + ) + self.list = async_to_raw_response_wrapper( + pools.list, + ) + self.delete = async_to_raw_response_wrapper( + pools.delete, + ) + self.get = async_to_raw_response_wrapper( + pools.get, + ) + + @cached_property + def health_monitors(self) -> AsyncHealthMonitorsResourceWithRawResponse: + return AsyncHealthMonitorsResourceWithRawResponse(self._pools.health_monitors) + + @cached_property + def members(self) -> AsyncMembersResourceWithRawResponse: + return AsyncMembersResourceWithRawResponse(self._pools.members) + + +class PoolsResourceWithStreamingResponse: + def __init__(self, pools: PoolsResource) -> None: + self._pools = pools + + self.create = to_streamed_response_wrapper( + pools.create, + ) + self.update = to_streamed_response_wrapper( + pools.update, + ) + self.list = to_streamed_response_wrapper( + pools.list, + ) + self.delete = to_streamed_response_wrapper( + pools.delete, + ) + self.get = to_streamed_response_wrapper( + pools.get, + ) + + @cached_property + def health_monitors(self) -> HealthMonitorsResourceWithStreamingResponse: + return HealthMonitorsResourceWithStreamingResponse(self._pools.health_monitors) + + @cached_property + def members(self) -> MembersResourceWithStreamingResponse: + return MembersResourceWithStreamingResponse(self._pools.members) + + +class AsyncPoolsResourceWithStreamingResponse: + def __init__(self, pools: AsyncPoolsResource) -> None: + self._pools = pools + + self.create = async_to_streamed_response_wrapper( + pools.create, + ) + self.update = async_to_streamed_response_wrapper( + pools.update, + ) + self.list = async_to_streamed_response_wrapper( + pools.list, + ) + self.delete = async_to_streamed_response_wrapper( + pools.delete, + ) + self.get = async_to_streamed_response_wrapper( + pools.get, + ) + + @cached_property + def health_monitors(self) -> AsyncHealthMonitorsResourceWithStreamingResponse: + return AsyncHealthMonitorsResourceWithStreamingResponse(self._pools.health_monitors) + + @cached_property + def members(self) -> AsyncMembersResourceWithStreamingResponse: + return AsyncMembersResourceWithStreamingResponse(self._pools.members) diff --git a/src/gcore/resources/cloud/load_balancers/statuses.py b/src/gcore/resources/cloud/load_balancers/statuses.py new file mode 100644 index 00000000..c2711ddd --- /dev/null +++ b/src/gcore/resources/cloud/load_balancers/statuses.py @@ -0,0 +1,280 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.load_balancer_status import LoadBalancerStatus +from ....types.cloud.load_balancer_status_list import LoadBalancerStatusList + +__all__ = ["StatusesResource", "AsyncStatusesResource"] + + +class StatusesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> StatusesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return StatusesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> StatusesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return StatusesResourceWithStreamingResponse(self) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerStatusList: + """ + List load balancers statuses + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/status", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerStatusList, + ) + + def get( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerStatus: + """ + Get load balancer status + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return self._get( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}/status", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerStatus, + ) + + +class AsyncStatusesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncStatusesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncStatusesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncStatusesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncStatusesResourceWithStreamingResponse(self) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerStatusList: + """ + List load balancers statuses + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/status", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerStatusList, + ) + + async def get( + self, + load_balancer_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LoadBalancerStatus: + """ + Get load balancer status + + Args: + project_id: Project ID + + region_id: Region ID + + load_balancer_id: Load-Balancer ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not load_balancer_id: + raise ValueError(f"Expected a non-empty value for `load_balancer_id` but received {load_balancer_id!r}") + return await self._get( + f"/cloud/v1/loadbalancers/{project_id}/{region_id}/{load_balancer_id}/status", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LoadBalancerStatus, + ) + + +class StatusesResourceWithRawResponse: + def __init__(self, statuses: StatusesResource) -> None: + self._statuses = statuses + + self.list = to_raw_response_wrapper( + statuses.list, + ) + self.get = to_raw_response_wrapper( + statuses.get, + ) + + +class AsyncStatusesResourceWithRawResponse: + def __init__(self, statuses: AsyncStatusesResource) -> None: + self._statuses = statuses + + self.list = async_to_raw_response_wrapper( + statuses.list, + ) + self.get = async_to_raw_response_wrapper( + statuses.get, + ) + + +class StatusesResourceWithStreamingResponse: + def __init__(self, statuses: StatusesResource) -> None: + self._statuses = statuses + + self.list = to_streamed_response_wrapper( + statuses.list, + ) + self.get = to_streamed_response_wrapper( + statuses.get, + ) + + +class AsyncStatusesResourceWithStreamingResponse: + def __init__(self, statuses: AsyncStatusesResource) -> None: + self._statuses = statuses + + self.list = async_to_streamed_response_wrapper( + statuses.list, + ) + self.get = async_to_streamed_response_wrapper( + statuses.get, + ) diff --git a/src/gcore/resources/cloud/networks/__init__.py b/src/gcore/resources/cloud/networks/__init__.py new file mode 100644 index 00000000..de3483b6 --- /dev/null +++ b/src/gcore/resources/cloud/networks/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .routers import ( + RoutersResource, + AsyncRoutersResource, + RoutersResourceWithRawResponse, + AsyncRoutersResourceWithRawResponse, + RoutersResourceWithStreamingResponse, + AsyncRoutersResourceWithStreamingResponse, +) +from .subnets import ( + SubnetsResource, + AsyncSubnetsResource, + SubnetsResourceWithRawResponse, + AsyncSubnetsResourceWithRawResponse, + SubnetsResourceWithStreamingResponse, + AsyncSubnetsResourceWithStreamingResponse, +) +from .networks import ( + NetworksResource, + AsyncNetworksResource, + NetworksResourceWithRawResponse, + AsyncNetworksResourceWithRawResponse, + NetworksResourceWithStreamingResponse, + AsyncNetworksResourceWithStreamingResponse, +) + +__all__ = [ + "SubnetsResource", + "AsyncSubnetsResource", + "SubnetsResourceWithRawResponse", + "AsyncSubnetsResourceWithRawResponse", + "SubnetsResourceWithStreamingResponse", + "AsyncSubnetsResourceWithStreamingResponse", + "RoutersResource", + "AsyncRoutersResource", + "RoutersResourceWithRawResponse", + "AsyncRoutersResourceWithRawResponse", + "RoutersResourceWithStreamingResponse", + "AsyncRoutersResourceWithStreamingResponse", + "NetworksResource", + "AsyncNetworksResource", + "NetworksResourceWithRawResponse", + "AsyncNetworksResourceWithRawResponse", + "NetworksResourceWithStreamingResponse", + "AsyncNetworksResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/networks/networks.py b/src/gcore/resources/cloud/networks/networks.py new file mode 100644 index 00000000..dc7e9f8a --- /dev/null +++ b/src/gcore/resources/cloud/networks/networks.py @@ -0,0 +1,841 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from .routers import ( + RoutersResource, + AsyncRoutersResource, + RoutersResourceWithRawResponse, + AsyncRoutersResourceWithRawResponse, + RoutersResourceWithStreamingResponse, + AsyncRoutersResourceWithStreamingResponse, +) +from .subnets import ( + SubnetsResource, + AsyncSubnetsResource, + SubnetsResourceWithRawResponse, + AsyncSubnetsResourceWithRawResponse, + SubnetsResourceWithStreamingResponse, + AsyncSubnetsResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ....types.cloud import network_list_params, network_create_params, network_update_params +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.network import Network +from ....types.cloud.task_id_list import TaskIDList +from ....types.cloud.tag_update_map_param import TagUpdateMapParam + +__all__ = ["NetworksResource", "AsyncNetworksResource"] + + +class NetworksResource(SyncAPIResource): + @cached_property + def subnets(self) -> SubnetsResource: + return SubnetsResource(self._client) + + @cached_property + def routers(self) -> RoutersResource: + return RoutersResource(self._client) + + @cached_property + def with_raw_response(self) -> NetworksResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return NetworksResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> NetworksResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return NetworksResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + create_router: bool | Omit = omit, + tags: object | Omit = omit, + type: Literal["vlan", "vxlan"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create network + + Args: + project_id: Project ID + + region_id: Region ID + + name: Network name + + create_router: Defaults to True + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + type: vlan or vxlan network type is allowed. Default value is vxlan + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/networks/{project_id}/{region_id}", + body=maybe_transform( + { + "name": name, + "create_router": create_router, + "tags": tags, + "type": type, + }, + network_create_params.NetworkCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + network_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Network: + """Rename network and/or update network tags. + + The request will only process the + fields that are provided in the request body. Any fields that are not included + will remain unchanged. + + Args: + project_id: Project ID + + region_id: Region ID + + network_id: Network ID + + name: Name. + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not network_id: + raise ValueError(f"Expected a non-empty value for `network_id` but received {network_id!r}") + return self._patch( + f"/cloud/v1/networks/{project_id}/{region_id}/{network_id}", + body=maybe_transform( + { + "name": name, + "tags": tags, + }, + network_update_params.NetworkUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Network, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["created_at.asc", "created_at.desc", "name.asc", "name.desc"] | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[Network]: + """ + List networks + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Optional. Limit the number of returned items + + name: Filter networks by name + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + order_by: Ordering networks list result by `name`, `created_at` fields of the network and + directions (`created_at.desc`). + + tag_key: Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2 + + tag_key_value: Optional. Filter by tag key-value pairs. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/networks/{project_id}/{region_id}", + page=SyncOffsetPage[Network], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "name": name, + "offset": offset, + "order_by": order_by, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + }, + network_list_params.NetworkListParams, + ), + ), + model=Network, + ) + + def delete( + self, + network_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete network + + Args: + project_id: Project ID + + region_id: Region ID + + network_id: Network ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not network_id: + raise ValueError(f"Expected a non-empty value for `network_id` but received {network_id!r}") + return self._delete( + f"/cloud/v1/networks/{project_id}/{region_id}/{network_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + network_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Network: + """ + Get network + + Args: + project_id: Project ID + + region_id: Region ID + + network_id: Network ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not network_id: + raise ValueError(f"Expected a non-empty value for `network_id` but received {network_id!r}") + return self._get( + f"/cloud/v1/networks/{project_id}/{region_id}/{network_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Network, + ) + + +class AsyncNetworksResource(AsyncAPIResource): + @cached_property + def subnets(self) -> AsyncSubnetsResource: + return AsyncSubnetsResource(self._client) + + @cached_property + def routers(self) -> AsyncRoutersResource: + return AsyncRoutersResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncNetworksResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncNetworksResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncNetworksResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncNetworksResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + create_router: bool | Omit = omit, + tags: object | Omit = omit, + type: Literal["vlan", "vxlan"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create network + + Args: + project_id: Project ID + + region_id: Region ID + + name: Network name + + create_router: Defaults to True + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + type: vlan or vxlan network type is allowed. Default value is vxlan + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/networks/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "name": name, + "create_router": create_router, + "tags": tags, + "type": type, + }, + network_create_params.NetworkCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + network_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Network: + """Rename network and/or update network tags. + + The request will only process the + fields that are provided in the request body. Any fields that are not included + will remain unchanged. + + Args: + project_id: Project ID + + region_id: Region ID + + network_id: Network ID + + name: Name. + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not network_id: + raise ValueError(f"Expected a non-empty value for `network_id` but received {network_id!r}") + return await self._patch( + f"/cloud/v1/networks/{project_id}/{region_id}/{network_id}", + body=await async_maybe_transform( + { + "name": name, + "tags": tags, + }, + network_update_params.NetworkUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Network, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["created_at.asc", "created_at.desc", "name.asc", "name.desc"] | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Network, AsyncOffsetPage[Network]]: + """ + List networks + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Optional. Limit the number of returned items + + name: Filter networks by name + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + order_by: Ordering networks list result by `name`, `created_at` fields of the network and + directions (`created_at.desc`). + + tag_key: Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2 + + tag_key_value: Optional. Filter by tag key-value pairs. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/networks/{project_id}/{region_id}", + page=AsyncOffsetPage[Network], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "name": name, + "offset": offset, + "order_by": order_by, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + }, + network_list_params.NetworkListParams, + ), + ), + model=Network, + ) + + async def delete( + self, + network_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete network + + Args: + project_id: Project ID + + region_id: Region ID + + network_id: Network ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not network_id: + raise ValueError(f"Expected a non-empty value for `network_id` but received {network_id!r}") + return await self._delete( + f"/cloud/v1/networks/{project_id}/{region_id}/{network_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + network_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Network: + """ + Get network + + Args: + project_id: Project ID + + region_id: Region ID + + network_id: Network ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not network_id: + raise ValueError(f"Expected a non-empty value for `network_id` but received {network_id!r}") + return await self._get( + f"/cloud/v1/networks/{project_id}/{region_id}/{network_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Network, + ) + + +class NetworksResourceWithRawResponse: + def __init__(self, networks: NetworksResource) -> None: + self._networks = networks + + self.create = to_raw_response_wrapper( + networks.create, + ) + self.update = to_raw_response_wrapper( + networks.update, + ) + self.list = to_raw_response_wrapper( + networks.list, + ) + self.delete = to_raw_response_wrapper( + networks.delete, + ) + self.get = to_raw_response_wrapper( + networks.get, + ) + + @cached_property + def subnets(self) -> SubnetsResourceWithRawResponse: + return SubnetsResourceWithRawResponse(self._networks.subnets) + + @cached_property + def routers(self) -> RoutersResourceWithRawResponse: + return RoutersResourceWithRawResponse(self._networks.routers) + + +class AsyncNetworksResourceWithRawResponse: + def __init__(self, networks: AsyncNetworksResource) -> None: + self._networks = networks + + self.create = async_to_raw_response_wrapper( + networks.create, + ) + self.update = async_to_raw_response_wrapper( + networks.update, + ) + self.list = async_to_raw_response_wrapper( + networks.list, + ) + self.delete = async_to_raw_response_wrapper( + networks.delete, + ) + self.get = async_to_raw_response_wrapper( + networks.get, + ) + + @cached_property + def subnets(self) -> AsyncSubnetsResourceWithRawResponse: + return AsyncSubnetsResourceWithRawResponse(self._networks.subnets) + + @cached_property + def routers(self) -> AsyncRoutersResourceWithRawResponse: + return AsyncRoutersResourceWithRawResponse(self._networks.routers) + + +class NetworksResourceWithStreamingResponse: + def __init__(self, networks: NetworksResource) -> None: + self._networks = networks + + self.create = to_streamed_response_wrapper( + networks.create, + ) + self.update = to_streamed_response_wrapper( + networks.update, + ) + self.list = to_streamed_response_wrapper( + networks.list, + ) + self.delete = to_streamed_response_wrapper( + networks.delete, + ) + self.get = to_streamed_response_wrapper( + networks.get, + ) + + @cached_property + def subnets(self) -> SubnetsResourceWithStreamingResponse: + return SubnetsResourceWithStreamingResponse(self._networks.subnets) + + @cached_property + def routers(self) -> RoutersResourceWithStreamingResponse: + return RoutersResourceWithStreamingResponse(self._networks.routers) + + +class AsyncNetworksResourceWithStreamingResponse: + def __init__(self, networks: AsyncNetworksResource) -> None: + self._networks = networks + + self.create = async_to_streamed_response_wrapper( + networks.create, + ) + self.update = async_to_streamed_response_wrapper( + networks.update, + ) + self.list = async_to_streamed_response_wrapper( + networks.list, + ) + self.delete = async_to_streamed_response_wrapper( + networks.delete, + ) + self.get = async_to_streamed_response_wrapper( + networks.get, + ) + + @cached_property + def subnets(self) -> AsyncSubnetsResourceWithStreamingResponse: + return AsyncSubnetsResourceWithStreamingResponse(self._networks.subnets) + + @cached_property + def routers(self) -> AsyncRoutersResourceWithStreamingResponse: + return AsyncRoutersResourceWithStreamingResponse(self._networks.routers) diff --git a/src/gcore/resources/cloud/networks/routers.py b/src/gcore/resources/cloud/networks/routers.py new file mode 100644 index 00000000..23ed228f --- /dev/null +++ b/src/gcore/resources/cloud/networks/routers.py @@ -0,0 +1,890 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import typing_extensions +from typing import Iterable, Optional + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.networks import ( + router_list_params, + router_create_params, + router_update_params, + router_attach_subnet_params, + router_detach_subnet_params, +) +from ....types.cloud.task_id_list import TaskIDList +from ....types.cloud.networks.router import Router + +__all__ = ["RoutersResource", "AsyncRoutersResource"] + + +class RoutersResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RoutersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return RoutersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RoutersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return RoutersResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + external_gateway_info: Optional[router_create_params.ExternalGatewayInfo] | Omit = omit, + interfaces: Optional[Iterable[router_create_params.Interface]] | Omit = omit, + routes: Optional[Iterable[router_create_params.Route]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new router with the specified configuration. + + Args: + name: name of router + + external_gateway_info + + interfaces: List of interfaces to attach to router immediately after creation. + + routes: List of custom routes. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/routers/{project_id}/{region_id}", + body=maybe_transform( + { + "name": name, + "external_gateway_info": external_gateway_info, + "interfaces": interfaces, + "routes": routes, + }, + router_create_params.RouterCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + @typing_extensions.deprecated("deprecated") + def update( + self, + router_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + external_gateway_info: Optional[router_update_params.ExternalGatewayInfo] | Omit = omit, + name: Optional[str] | Omit = omit, + routes: Optional[Iterable[router_update_params.Route]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Router: + """Update the configuration of an existing router. + + **Deprecated**: Use + `PATCH /v2/routers/{project_id}/{region_id}/{router_id}` instead. + + Args: + external_gateway_info: New external gateway. + + name: New name of router + + routes: List of custom routes. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not router_id: + raise ValueError(f"Expected a non-empty value for `router_id` but received {router_id!r}") + return self._patch( + f"/cloud/v1/routers/{project_id}/{region_id}/{router_id}", + body=maybe_transform( + { + "external_gateway_info": external_gateway_info, + "name": name, + "routes": routes, + }, + router_update_params.RouterUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Router, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[Router]: + """ + List all routers in the specified project and region. + + Args: + limit: Limit the number of returned routers + + offset: Offset value is used to exclude the first set of records from the result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/routers/{project_id}/{region_id}", + page=SyncOffsetPage[Router], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + router_list_params.RouterListParams, + ), + ), + model=Router, + ) + + def delete( + self, + router_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a specific router and all its associated resources. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not router_id: + raise ValueError(f"Expected a non-empty value for `router_id` but received {router_id!r}") + return self._delete( + f"/cloud/v1/routers/{project_id}/{region_id}/{router_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def attach_subnet( + self, + router_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + subnet_id: str, + ip_address: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Router: + """ + Attach a subnet to an existing router. + + Args: + project_id: Project ID + + region_id: Region ID + + router_id: Router ID + + subnet_id: Subnet ID on which router interface will be created + + ip_address: IP address to assign for router's interface, if not specified, address will be + selected automatically + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not router_id: + raise ValueError(f"Expected a non-empty value for `router_id` but received {router_id!r}") + return self._post( + f"/cloud/v1/routers/{project_id}/{region_id}/{router_id}/attach", + body=maybe_transform( + { + "subnet_id": subnet_id, + "ip_address": ip_address, + }, + router_attach_subnet_params.RouterAttachSubnetParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Router, + ) + + def detach_subnet( + self, + router_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + subnet_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Router: + """ + Detach a subnet from an existing router. + + Args: + subnet_id: Target IP is identified by it's subnet + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not router_id: + raise ValueError(f"Expected a non-empty value for `router_id` but received {router_id!r}") + return self._post( + f"/cloud/v1/routers/{project_id}/{region_id}/{router_id}/detach", + body=maybe_transform({"subnet_id": subnet_id}, router_detach_subnet_params.RouterDetachSubnetParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Router, + ) + + def get( + self, + router_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Router: + """ + Get detailed information about a specific router. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not router_id: + raise ValueError(f"Expected a non-empty value for `router_id` but received {router_id!r}") + return self._get( + f"/cloud/v1/routers/{project_id}/{region_id}/{router_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Router, + ) + + +class AsyncRoutersResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRoutersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncRoutersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRoutersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncRoutersResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + external_gateway_info: Optional[router_create_params.ExternalGatewayInfo] | Omit = omit, + interfaces: Optional[Iterable[router_create_params.Interface]] | Omit = omit, + routes: Optional[Iterable[router_create_params.Route]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new router with the specified configuration. + + Args: + name: name of router + + external_gateway_info + + interfaces: List of interfaces to attach to router immediately after creation. + + routes: List of custom routes. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/routers/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "name": name, + "external_gateway_info": external_gateway_info, + "interfaces": interfaces, + "routes": routes, + }, + router_create_params.RouterCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + @typing_extensions.deprecated("deprecated") + async def update( + self, + router_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + external_gateway_info: Optional[router_update_params.ExternalGatewayInfo] | Omit = omit, + name: Optional[str] | Omit = omit, + routes: Optional[Iterable[router_update_params.Route]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Router: + """Update the configuration of an existing router. + + **Deprecated**: Use + `PATCH /v2/routers/{project_id}/{region_id}/{router_id}` instead. + + Args: + external_gateway_info: New external gateway. + + name: New name of router + + routes: List of custom routes. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not router_id: + raise ValueError(f"Expected a non-empty value for `router_id` but received {router_id!r}") + return await self._patch( + f"/cloud/v1/routers/{project_id}/{region_id}/{router_id}", + body=await async_maybe_transform( + { + "external_gateway_info": external_gateway_info, + "name": name, + "routes": routes, + }, + router_update_params.RouterUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Router, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Router, AsyncOffsetPage[Router]]: + """ + List all routers in the specified project and region. + + Args: + limit: Limit the number of returned routers + + offset: Offset value is used to exclude the first set of records from the result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/routers/{project_id}/{region_id}", + page=AsyncOffsetPage[Router], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + router_list_params.RouterListParams, + ), + ), + model=Router, + ) + + async def delete( + self, + router_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a specific router and all its associated resources. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not router_id: + raise ValueError(f"Expected a non-empty value for `router_id` but received {router_id!r}") + return await self._delete( + f"/cloud/v1/routers/{project_id}/{region_id}/{router_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def attach_subnet( + self, + router_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + subnet_id: str, + ip_address: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Router: + """ + Attach a subnet to an existing router. + + Args: + project_id: Project ID + + region_id: Region ID + + router_id: Router ID + + subnet_id: Subnet ID on which router interface will be created + + ip_address: IP address to assign for router's interface, if not specified, address will be + selected automatically + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not router_id: + raise ValueError(f"Expected a non-empty value for `router_id` but received {router_id!r}") + return await self._post( + f"/cloud/v1/routers/{project_id}/{region_id}/{router_id}/attach", + body=await async_maybe_transform( + { + "subnet_id": subnet_id, + "ip_address": ip_address, + }, + router_attach_subnet_params.RouterAttachSubnetParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Router, + ) + + async def detach_subnet( + self, + router_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + subnet_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Router: + """ + Detach a subnet from an existing router. + + Args: + subnet_id: Target IP is identified by it's subnet + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not router_id: + raise ValueError(f"Expected a non-empty value for `router_id` but received {router_id!r}") + return await self._post( + f"/cloud/v1/routers/{project_id}/{region_id}/{router_id}/detach", + body=await async_maybe_transform( + {"subnet_id": subnet_id}, router_detach_subnet_params.RouterDetachSubnetParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Router, + ) + + async def get( + self, + router_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Router: + """ + Get detailed information about a specific router. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not router_id: + raise ValueError(f"Expected a non-empty value for `router_id` but received {router_id!r}") + return await self._get( + f"/cloud/v1/routers/{project_id}/{region_id}/{router_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Router, + ) + + +class RoutersResourceWithRawResponse: + def __init__(self, routers: RoutersResource) -> None: + self._routers = routers + + self.create = to_raw_response_wrapper( + routers.create, + ) + self.update = ( # pyright: ignore[reportDeprecated] + to_raw_response_wrapper( + routers.update, # pyright: ignore[reportDeprecated], + ) + ) + self.list = to_raw_response_wrapper( + routers.list, + ) + self.delete = to_raw_response_wrapper( + routers.delete, + ) + self.attach_subnet = to_raw_response_wrapper( + routers.attach_subnet, + ) + self.detach_subnet = to_raw_response_wrapper( + routers.detach_subnet, + ) + self.get = to_raw_response_wrapper( + routers.get, + ) + + +class AsyncRoutersResourceWithRawResponse: + def __init__(self, routers: AsyncRoutersResource) -> None: + self._routers = routers + + self.create = async_to_raw_response_wrapper( + routers.create, + ) + self.update = ( # pyright: ignore[reportDeprecated] + async_to_raw_response_wrapper( + routers.update, # pyright: ignore[reportDeprecated], + ) + ) + self.list = async_to_raw_response_wrapper( + routers.list, + ) + self.delete = async_to_raw_response_wrapper( + routers.delete, + ) + self.attach_subnet = async_to_raw_response_wrapper( + routers.attach_subnet, + ) + self.detach_subnet = async_to_raw_response_wrapper( + routers.detach_subnet, + ) + self.get = async_to_raw_response_wrapper( + routers.get, + ) + + +class RoutersResourceWithStreamingResponse: + def __init__(self, routers: RoutersResource) -> None: + self._routers = routers + + self.create = to_streamed_response_wrapper( + routers.create, + ) + self.update = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + routers.update, # pyright: ignore[reportDeprecated], + ) + ) + self.list = to_streamed_response_wrapper( + routers.list, + ) + self.delete = to_streamed_response_wrapper( + routers.delete, + ) + self.attach_subnet = to_streamed_response_wrapper( + routers.attach_subnet, + ) + self.detach_subnet = to_streamed_response_wrapper( + routers.detach_subnet, + ) + self.get = to_streamed_response_wrapper( + routers.get, + ) + + +class AsyncRoutersResourceWithStreamingResponse: + def __init__(self, routers: AsyncRoutersResource) -> None: + self._routers = routers + + self.create = async_to_streamed_response_wrapper( + routers.create, + ) + self.update = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + routers.update, # pyright: ignore[reportDeprecated], + ) + ) + self.list = async_to_streamed_response_wrapper( + routers.list, + ) + self.delete = async_to_streamed_response_wrapper( + routers.delete, + ) + self.attach_subnet = async_to_streamed_response_wrapper( + routers.attach_subnet, + ) + self.detach_subnet = async_to_streamed_response_wrapper( + routers.detach_subnet, + ) + self.get = async_to_streamed_response_wrapper( + routers.get, + ) diff --git a/src/gcore/resources/cloud/networks/subnets.py b/src/gcore/resources/cloud/networks/subnets.py new file mode 100644 index 00000000..b2861e1f --- /dev/null +++ b/src/gcore/resources/cloud/networks/subnets.py @@ -0,0 +1,909 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ....types.cloud import IPVersion +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.subnet import Subnet +from ....types.cloud.networks import subnet_list_params, subnet_create_params, subnet_update_params +from ....types.cloud.ip_version import IPVersion +from ....types.cloud.task_id_list import TaskIDList +from ....types.cloud.tag_update_map_param import TagUpdateMapParam + +__all__ = ["SubnetsResource", "AsyncSubnetsResource"] + + +class SubnetsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SubnetsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return SubnetsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SubnetsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return SubnetsResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + cidr: str, + name: str, + network_id: str, + connect_to_network_router: bool | Omit = omit, + dns_nameservers: Optional[SequenceNotStr[str]] | Omit = omit, + enable_dhcp: bool | Omit = omit, + gateway_ip: Optional[str] | Omit = omit, + host_routes: Optional[Iterable[subnet_create_params.HostRoute]] | Omit = omit, + ip_version: IPVersion | Omit = omit, + router_id_to_connect: Optional[str] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create subnet + + Args: + project_id: Project ID + + region_id: Region ID + + cidr: CIDR + + name: Subnet name + + network_id: Network ID + + connect_to_network_router: True if the network's router should get a gateway in this subnet. Must be + explicitly 'false' when `gateway_ip` is null. + + dns_nameservers: List IP addresses of DNS servers to advertise via DHCP. + + enable_dhcp: True if DHCP should be enabled + + gateway_ip: Default GW IPv4 address to advertise in DHCP routes in this subnet. Omit this + field to let the cloud backend allocate it automatically. Set to null if no + gateway must be advertised by this subnet's DHCP (useful when attaching + instances to multiple subnets in order to prevent default route conflicts). + + host_routes: List of custom static routes to advertise via DHCP. + + ip_version: IP version + + router_id_to_connect: ID of the router to connect to. Requires `connect_to_network_router` set to + true. If not specified, attempts to find a router created during network + creation. + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/subnets/{project_id}/{region_id}", + body=maybe_transform( + { + "cidr": cidr, + "name": name, + "network_id": network_id, + "connect_to_network_router": connect_to_network_router, + "dns_nameservers": dns_nameservers, + "enable_dhcp": enable_dhcp, + "gateway_ip": gateway_ip, + "host_routes": host_routes, + "ip_version": ip_version, + "router_id_to_connect": router_id_to_connect, + "tags": tags, + }, + subnet_create_params.SubnetCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + subnet_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + dns_nameservers: Optional[SequenceNotStr[str]] | Omit = omit, + enable_dhcp: bool | Omit = omit, + gateway_ip: Optional[str] | Omit = omit, + host_routes: Optional[Iterable[subnet_update_params.HostRoute]] | Omit = omit, + name: Optional[str] | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Subnet: + """ + Update subnet + + Args: + project_id: Project ID + + region_id: Region ID + + subnet_id: Subnet ID + + dns_nameservers: List IP addresses of DNS servers to advertise via DHCP. + + enable_dhcp: True if DHCP should be enabled + + gateway_ip: Default GW IPv4 address to advertise in DHCP routes in this subnet. Omit this + field to let the cloud backend allocate it automatically. Set to null if no + gateway must be advertised by this subnet's DHCP (useful when attaching + instances to multiple subnets in order to prevent default route conflicts). + + host_routes: List of custom static routes to advertise via DHCP. + + name: Name + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not subnet_id: + raise ValueError(f"Expected a non-empty value for `subnet_id` but received {subnet_id!r}") + return self._patch( + f"/cloud/v1/subnets/{project_id}/{region_id}/{subnet_id}", + body=maybe_transform( + { + "dns_nameservers": dns_nameservers, + "enable_dhcp": enable_dhcp, + "gateway_ip": gateway_ip, + "host_routes": host_routes, + "name": name, + "tags": tags, + }, + subnet_update_params.SubnetUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Subnet, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + network_id: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal[ + "available_ips.asc", + "available_ips.desc", + "cidr.asc", + "cidr.desc", + "created_at.asc", + "created_at.desc", + "name.asc", + "name.desc", + "total_ips.asc", + "total_ips.desc", + "updated_at.asc", + "updated_at.desc", + ] + | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[Subnet]: + """ + List subnets + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Optional. Limit the number of returned items + + network_id: Only list subnets of this network + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + order_by: Ordering subnets list result by `name`, `created_at`, `updated_at`, + `available_ips`, `total_ips`, and `cidr` (default) fields of the subnet and + directions (`name.asc`). + + tag_key: Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2 + + tag_key_value: Optional. Filter by tag key-value pairs. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/subnets/{project_id}/{region_id}", + page=SyncOffsetPage[Subnet], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "network_id": network_id, + "offset": offset, + "order_by": order_by, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + }, + subnet_list_params.SubnetListParams, + ), + ), + model=Subnet, + ) + + def delete( + self, + subnet_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete subnet + + Args: + project_id: Project ID + + region_id: Region ID + + subnet_id: Subnet ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not subnet_id: + raise ValueError(f"Expected a non-empty value for `subnet_id` but received {subnet_id!r}") + return self._delete( + f"/cloud/v1/subnets/{project_id}/{region_id}/{subnet_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + subnet_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Subnet: + """ + Get subnet + + Args: + project_id: Project ID + + region_id: Region ID + + subnet_id: Subnet ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not subnet_id: + raise ValueError(f"Expected a non-empty value for `subnet_id` but received {subnet_id!r}") + return self._get( + f"/cloud/v1/subnets/{project_id}/{region_id}/{subnet_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Subnet, + ) + + +class AsyncSubnetsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSubnetsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncSubnetsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSubnetsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncSubnetsResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + cidr: str, + name: str, + network_id: str, + connect_to_network_router: bool | Omit = omit, + dns_nameservers: Optional[SequenceNotStr[str]] | Omit = omit, + enable_dhcp: bool | Omit = omit, + gateway_ip: Optional[str] | Omit = omit, + host_routes: Optional[Iterable[subnet_create_params.HostRoute]] | Omit = omit, + ip_version: IPVersion | Omit = omit, + router_id_to_connect: Optional[str] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create subnet + + Args: + project_id: Project ID + + region_id: Region ID + + cidr: CIDR + + name: Subnet name + + network_id: Network ID + + connect_to_network_router: True if the network's router should get a gateway in this subnet. Must be + explicitly 'false' when `gateway_ip` is null. + + dns_nameservers: List IP addresses of DNS servers to advertise via DHCP. + + enable_dhcp: True if DHCP should be enabled + + gateway_ip: Default GW IPv4 address to advertise in DHCP routes in this subnet. Omit this + field to let the cloud backend allocate it automatically. Set to null if no + gateway must be advertised by this subnet's DHCP (useful when attaching + instances to multiple subnets in order to prevent default route conflicts). + + host_routes: List of custom static routes to advertise via DHCP. + + ip_version: IP version + + router_id_to_connect: ID of the router to connect to. Requires `connect_to_network_router` set to + true. If not specified, attempts to find a router created during network + creation. + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/subnets/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "cidr": cidr, + "name": name, + "network_id": network_id, + "connect_to_network_router": connect_to_network_router, + "dns_nameservers": dns_nameservers, + "enable_dhcp": enable_dhcp, + "gateway_ip": gateway_ip, + "host_routes": host_routes, + "ip_version": ip_version, + "router_id_to_connect": router_id_to_connect, + "tags": tags, + }, + subnet_create_params.SubnetCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + subnet_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + dns_nameservers: Optional[SequenceNotStr[str]] | Omit = omit, + enable_dhcp: bool | Omit = omit, + gateway_ip: Optional[str] | Omit = omit, + host_routes: Optional[Iterable[subnet_update_params.HostRoute]] | Omit = omit, + name: Optional[str] | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Subnet: + """ + Update subnet + + Args: + project_id: Project ID + + region_id: Region ID + + subnet_id: Subnet ID + + dns_nameservers: List IP addresses of DNS servers to advertise via DHCP. + + enable_dhcp: True if DHCP should be enabled + + gateway_ip: Default GW IPv4 address to advertise in DHCP routes in this subnet. Omit this + field to let the cloud backend allocate it automatically. Set to null if no + gateway must be advertised by this subnet's DHCP (useful when attaching + instances to multiple subnets in order to prevent default route conflicts). + + host_routes: List of custom static routes to advertise via DHCP. + + name: Name + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not subnet_id: + raise ValueError(f"Expected a non-empty value for `subnet_id` but received {subnet_id!r}") + return await self._patch( + f"/cloud/v1/subnets/{project_id}/{region_id}/{subnet_id}", + body=await async_maybe_transform( + { + "dns_nameservers": dns_nameservers, + "enable_dhcp": enable_dhcp, + "gateway_ip": gateway_ip, + "host_routes": host_routes, + "name": name, + "tags": tags, + }, + subnet_update_params.SubnetUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Subnet, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + network_id: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal[ + "available_ips.asc", + "available_ips.desc", + "cidr.asc", + "cidr.desc", + "created_at.asc", + "created_at.desc", + "name.asc", + "name.desc", + "total_ips.asc", + "total_ips.desc", + "updated_at.asc", + "updated_at.desc", + ] + | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Subnet, AsyncOffsetPage[Subnet]]: + """ + List subnets + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Optional. Limit the number of returned items + + network_id: Only list subnets of this network + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + order_by: Ordering subnets list result by `name`, `created_at`, `updated_at`, + `available_ips`, `total_ips`, and `cidr` (default) fields of the subnet and + directions (`name.asc`). + + tag_key: Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2 + + tag_key_value: Optional. Filter by tag key-value pairs. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/subnets/{project_id}/{region_id}", + page=AsyncOffsetPage[Subnet], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "network_id": network_id, + "offset": offset, + "order_by": order_by, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + }, + subnet_list_params.SubnetListParams, + ), + ), + model=Subnet, + ) + + async def delete( + self, + subnet_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete subnet + + Args: + project_id: Project ID + + region_id: Region ID + + subnet_id: Subnet ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not subnet_id: + raise ValueError(f"Expected a non-empty value for `subnet_id` but received {subnet_id!r}") + return await self._delete( + f"/cloud/v1/subnets/{project_id}/{region_id}/{subnet_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + subnet_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Subnet: + """ + Get subnet + + Args: + project_id: Project ID + + region_id: Region ID + + subnet_id: Subnet ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not subnet_id: + raise ValueError(f"Expected a non-empty value for `subnet_id` but received {subnet_id!r}") + return await self._get( + f"/cloud/v1/subnets/{project_id}/{region_id}/{subnet_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Subnet, + ) + + +class SubnetsResourceWithRawResponse: + def __init__(self, subnets: SubnetsResource) -> None: + self._subnets = subnets + + self.create = to_raw_response_wrapper( + subnets.create, + ) + self.update = to_raw_response_wrapper( + subnets.update, + ) + self.list = to_raw_response_wrapper( + subnets.list, + ) + self.delete = to_raw_response_wrapper( + subnets.delete, + ) + self.get = to_raw_response_wrapper( + subnets.get, + ) + + +class AsyncSubnetsResourceWithRawResponse: + def __init__(self, subnets: AsyncSubnetsResource) -> None: + self._subnets = subnets + + self.create = async_to_raw_response_wrapper( + subnets.create, + ) + self.update = async_to_raw_response_wrapper( + subnets.update, + ) + self.list = async_to_raw_response_wrapper( + subnets.list, + ) + self.delete = async_to_raw_response_wrapper( + subnets.delete, + ) + self.get = async_to_raw_response_wrapper( + subnets.get, + ) + + +class SubnetsResourceWithStreamingResponse: + def __init__(self, subnets: SubnetsResource) -> None: + self._subnets = subnets + + self.create = to_streamed_response_wrapper( + subnets.create, + ) + self.update = to_streamed_response_wrapper( + subnets.update, + ) + self.list = to_streamed_response_wrapper( + subnets.list, + ) + self.delete = to_streamed_response_wrapper( + subnets.delete, + ) + self.get = to_streamed_response_wrapper( + subnets.get, + ) + + +class AsyncSubnetsResourceWithStreamingResponse: + def __init__(self, subnets: AsyncSubnetsResource) -> None: + self._subnets = subnets + + self.create = async_to_streamed_response_wrapper( + subnets.create, + ) + self.update = async_to_streamed_response_wrapper( + subnets.update, + ) + self.list = async_to_streamed_response_wrapper( + subnets.list, + ) + self.delete = async_to_streamed_response_wrapper( + subnets.delete, + ) + self.get = async_to_streamed_response_wrapper( + subnets.get, + ) diff --git a/src/gcore/resources/cloud/placement_groups.py b/src/gcore/resources/cloud/placement_groups.py new file mode 100644 index 00000000..243dd294 --- /dev/null +++ b/src/gcore/resources/cloud/placement_groups.py @@ -0,0 +1,473 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cloud import placement_group_create_params +from ..._base_client import make_request_options +from ...types.cloud.task_id_list import TaskIDList +from ...types.cloud.placement_group import PlacementGroup +from ...types.cloud.placement_group_list import PlacementGroupList + +__all__ = ["PlacementGroupsResource", "AsyncPlacementGroupsResource"] + + +class PlacementGroupsResource(SyncAPIResource): + """ + Placement Groups allow you to specific a policy that determines whether Virtual Machines will be hosted on the same physical server or on different ones. + """ + + @cached_property + def with_raw_response(self) -> PlacementGroupsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return PlacementGroupsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PlacementGroupsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return PlacementGroupsResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + policy: Literal["affinity", "anti-affinity", "soft-anti-affinity"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlacementGroup: + """ + Create an affinity or anti-affinity or soft-anti-affinity placement group + + Args: + name: The name of the server group. + + policy: The server group policy. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/servergroups/{project_id}/{region_id}", + body=maybe_transform( + { + "name": name, + "policy": policy, + }, + placement_group_create_params.PlacementGroupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlacementGroup, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlacementGroupList: + """ + List placement groups + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/servergroups/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlacementGroupList, + ) + + def delete( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete placement group + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._delete( + f"/cloud/v1/servergroups/{project_id}/{region_id}/{group_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlacementGroup: + """ + Get placement group + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._get( + f"/cloud/v1/servergroups/{project_id}/{region_id}/{group_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlacementGroup, + ) + + +class AsyncPlacementGroupsResource(AsyncAPIResource): + """ + Placement Groups allow you to specific a policy that determines whether Virtual Machines will be hosted on the same physical server or on different ones. + """ + + @cached_property + def with_raw_response(self) -> AsyncPlacementGroupsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncPlacementGroupsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPlacementGroupsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncPlacementGroupsResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + policy: Literal["affinity", "anti-affinity", "soft-anti-affinity"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlacementGroup: + """ + Create an affinity or anti-affinity or soft-anti-affinity placement group + + Args: + name: The name of the server group. + + policy: The server group policy. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/servergroups/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "name": name, + "policy": policy, + }, + placement_group_create_params.PlacementGroupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlacementGroup, + ) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlacementGroupList: + """ + List placement groups + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/servergroups/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlacementGroupList, + ) + + async def delete( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete placement group + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._delete( + f"/cloud/v1/servergroups/{project_id}/{region_id}/{group_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlacementGroup: + """ + Get placement group + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._get( + f"/cloud/v1/servergroups/{project_id}/{region_id}/{group_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlacementGroup, + ) + + +class PlacementGroupsResourceWithRawResponse: + def __init__(self, placement_groups: PlacementGroupsResource) -> None: + self._placement_groups = placement_groups + + self.create = to_raw_response_wrapper( + placement_groups.create, + ) + self.list = to_raw_response_wrapper( + placement_groups.list, + ) + self.delete = to_raw_response_wrapper( + placement_groups.delete, + ) + self.get = to_raw_response_wrapper( + placement_groups.get, + ) + + +class AsyncPlacementGroupsResourceWithRawResponse: + def __init__(self, placement_groups: AsyncPlacementGroupsResource) -> None: + self._placement_groups = placement_groups + + self.create = async_to_raw_response_wrapper( + placement_groups.create, + ) + self.list = async_to_raw_response_wrapper( + placement_groups.list, + ) + self.delete = async_to_raw_response_wrapper( + placement_groups.delete, + ) + self.get = async_to_raw_response_wrapper( + placement_groups.get, + ) + + +class PlacementGroupsResourceWithStreamingResponse: + def __init__(self, placement_groups: PlacementGroupsResource) -> None: + self._placement_groups = placement_groups + + self.create = to_streamed_response_wrapper( + placement_groups.create, + ) + self.list = to_streamed_response_wrapper( + placement_groups.list, + ) + self.delete = to_streamed_response_wrapper( + placement_groups.delete, + ) + self.get = to_streamed_response_wrapper( + placement_groups.get, + ) + + +class AsyncPlacementGroupsResourceWithStreamingResponse: + def __init__(self, placement_groups: AsyncPlacementGroupsResource) -> None: + self._placement_groups = placement_groups + + self.create = async_to_streamed_response_wrapper( + placement_groups.create, + ) + self.list = async_to_streamed_response_wrapper( + placement_groups.list, + ) + self.delete = async_to_streamed_response_wrapper( + placement_groups.delete, + ) + self.get = async_to_streamed_response_wrapper( + placement_groups.get, + ) diff --git a/src/gcore/resources/cloud/projects.py b/src/gcore/resources/cloud/projects.py new file mode 100644 index 00000000..f8c47c0c --- /dev/null +++ b/src/gcore/resources/cloud/projects.py @@ -0,0 +1,618 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ...types.cloud import project_list_params, project_create_params, project_update_params +from ..._base_client import AsyncPaginator, make_request_options +from ...types.cloud.project import Project +from ...types.cloud.task_id_list import TaskIDList + +__all__ = ["ProjectsResource", "AsyncProjectsResource"] + + +class ProjectsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ProjectsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ProjectsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ProjectsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ProjectsResourceWithStreamingResponse(self) + + def create( + self, + *, + name: str, + description: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """Create a new project for a client. + + Project management must be enabled to perform + this operation. + + Args: + name: Unique project name for a client. Each client always has one "default" project. + + description: Description of the project. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/cloud/v1/projects", + body=maybe_transform( + { + "name": name, + "description": description, + }, + project_create_params.ProjectCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Project, + ) + + def update( + self, + *, + project_id: int | None = None, + description: str | Omit = omit, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """ + This endpoint allows partial updates of a project (such as its name or + description). Only the fields explicitly provided in the request body will be + updated. + + Args: + project_id: Project ID + + description: Description of the project. + + name: Name of the entity, following a specific format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._patch( + f"/cloud/v1/projects/{project_id}", + body=maybe_transform( + { + "description": description, + "name": name, + }, + project_update_params.ProjectUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Project, + ) + + def list( + self, + *, + client_id: int | Omit = omit, + include_deleted: bool | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["created_at.asc", "created_at.desc", "name.asc", "name.desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[Project]: + """Retrieve a list of projects for a client. + + Results can be filtered by name and + ordered by various fields. + + Args: + client_id: Client ID filter for administrators. + + include_deleted: Whether to include deleted projects in the response. + + limit: Limit value is used to limit the number of records in the result + + name: Name to filter the results by. + + offset: Offset value is used to exclude the first set of records from the result + + order_by: Order by field and direction. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v1/projects", + page=SyncOffsetPage[Project], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "client_id": client_id, + "include_deleted": include_deleted, + "limit": limit, + "name": name, + "offset": offset, + "order_by": order_by, + }, + project_list_params.ProjectListParams, + ), + ), + model=Project, + ) + + def delete( + self, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Delete a project and all its associated cloud resources across all regions. + + This + operation is irreversible and cannot be undone. Default projects cannot be + deleted. + + Args: + project_id: Project ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._delete( + f"/cloud/v1/projects/{project_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """ + Retrieve detailed information about a specific project. + + Args: + project_id: Project ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._get( + f"/cloud/v1/projects/{project_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Project, + ) + + +class AsyncProjectsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncProjectsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncProjectsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncProjectsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncProjectsResourceWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + description: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """Create a new project for a client. + + Project management must be enabled to perform + this operation. + + Args: + name: Unique project name for a client. Each client always has one "default" project. + + description: Description of the project. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/cloud/v1/projects", + body=await async_maybe_transform( + { + "name": name, + "description": description, + }, + project_create_params.ProjectCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Project, + ) + + async def update( + self, + *, + project_id: int | None = None, + description: str | Omit = omit, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """ + This endpoint allows partial updates of a project (such as its name or + description). Only the fields explicitly provided in the request body will be + updated. + + Args: + project_id: Project ID + + description: Description of the project. + + name: Name of the entity, following a specific format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return await self._patch( + f"/cloud/v1/projects/{project_id}", + body=await async_maybe_transform( + { + "description": description, + "name": name, + }, + project_update_params.ProjectUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Project, + ) + + def list( + self, + *, + client_id: int | Omit = omit, + include_deleted: bool | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["created_at.asc", "created_at.desc", "name.asc", "name.desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Project, AsyncOffsetPage[Project]]: + """Retrieve a list of projects for a client. + + Results can be filtered by name and + ordered by various fields. + + Args: + client_id: Client ID filter for administrators. + + include_deleted: Whether to include deleted projects in the response. + + limit: Limit value is used to limit the number of records in the result + + name: Name to filter the results by. + + offset: Offset value is used to exclude the first set of records from the result + + order_by: Order by field and direction. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v1/projects", + page=AsyncOffsetPage[Project], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "client_id": client_id, + "include_deleted": include_deleted, + "limit": limit, + "name": name, + "offset": offset, + "order_by": order_by, + }, + project_list_params.ProjectListParams, + ), + ), + model=Project, + ) + + async def delete( + self, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Delete a project and all its associated cloud resources across all regions. + + This + operation is irreversible and cannot be undone. Default projects cannot be + deleted. + + Args: + project_id: Project ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return await self._delete( + f"/cloud/v1/projects/{project_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Project: + """ + Retrieve detailed information about a specific project. + + Args: + project_id: Project ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return await self._get( + f"/cloud/v1/projects/{project_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Project, + ) + + +class ProjectsResourceWithRawResponse: + def __init__(self, projects: ProjectsResource) -> None: + self._projects = projects + + self.create = to_raw_response_wrapper( + projects.create, + ) + self.update = to_raw_response_wrapper( + projects.update, + ) + self.list = to_raw_response_wrapper( + projects.list, + ) + self.delete = to_raw_response_wrapper( + projects.delete, + ) + self.get = to_raw_response_wrapper( + projects.get, + ) + + +class AsyncProjectsResourceWithRawResponse: + def __init__(self, projects: AsyncProjectsResource) -> None: + self._projects = projects + + self.create = async_to_raw_response_wrapper( + projects.create, + ) + self.update = async_to_raw_response_wrapper( + projects.update, + ) + self.list = async_to_raw_response_wrapper( + projects.list, + ) + self.delete = async_to_raw_response_wrapper( + projects.delete, + ) + self.get = async_to_raw_response_wrapper( + projects.get, + ) + + +class ProjectsResourceWithStreamingResponse: + def __init__(self, projects: ProjectsResource) -> None: + self._projects = projects + + self.create = to_streamed_response_wrapper( + projects.create, + ) + self.update = to_streamed_response_wrapper( + projects.update, + ) + self.list = to_streamed_response_wrapper( + projects.list, + ) + self.delete = to_streamed_response_wrapper( + projects.delete, + ) + self.get = to_streamed_response_wrapper( + projects.get, + ) + + +class AsyncProjectsResourceWithStreamingResponse: + def __init__(self, projects: AsyncProjectsResource) -> None: + self._projects = projects + + self.create = async_to_streamed_response_wrapper( + projects.create, + ) + self.update = async_to_streamed_response_wrapper( + projects.update, + ) + self.list = async_to_streamed_response_wrapper( + projects.list, + ) + self.delete = async_to_streamed_response_wrapper( + projects.delete, + ) + self.get = async_to_streamed_response_wrapper( + projects.get, + ) diff --git a/src/gcore/resources/cloud/quotas/__init__.py b/src/gcore/resources/cloud/quotas/__init__.py new file mode 100644 index 00000000..5d09d00d --- /dev/null +++ b/src/gcore/resources/cloud/quotas/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .quotas import ( + QuotasResource, + AsyncQuotasResource, + QuotasResourceWithRawResponse, + AsyncQuotasResourceWithRawResponse, + QuotasResourceWithStreamingResponse, + AsyncQuotasResourceWithStreamingResponse, +) +from .requests import ( + RequestsResource, + AsyncRequestsResource, + RequestsResourceWithRawResponse, + AsyncRequestsResourceWithRawResponse, + RequestsResourceWithStreamingResponse, + AsyncRequestsResourceWithStreamingResponse, +) + +__all__ = [ + "RequestsResource", + "AsyncRequestsResource", + "RequestsResourceWithRawResponse", + "AsyncRequestsResourceWithRawResponse", + "RequestsResourceWithStreamingResponse", + "AsyncRequestsResourceWithStreamingResponse", + "QuotasResource", + "AsyncQuotasResource", + "QuotasResourceWithRawResponse", + "AsyncQuotasResourceWithRawResponse", + "QuotasResourceWithStreamingResponse", + "AsyncQuotasResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/quotas/quotas.py b/src/gcore/resources/cloud/quotas/quotas.py new file mode 100644 index 00000000..915d900d --- /dev/null +++ b/src/gcore/resources/cloud/quotas/quotas.py @@ -0,0 +1,335 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .requests import ( + RequestsResource, + AsyncRequestsResource, + RequestsResourceWithRawResponse, + AsyncRequestsResourceWithRawResponse, + RequestsResourceWithStreamingResponse, + AsyncRequestsResourceWithStreamingResponse, +) +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.quota_get_all_response import QuotaGetAllResponse +from ....types.cloud.quota_get_global_response import QuotaGetGlobalResponse +from ....types.cloud.quota_get_by_region_response import QuotaGetByRegionResponse + +__all__ = ["QuotasResource", "AsyncQuotasResource"] + + +class QuotasResource(SyncAPIResource): + @cached_property + def requests(self) -> RequestsResource: + return RequestsResource(self._client) + + @cached_property + def with_raw_response(self) -> QuotasResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return QuotasResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> QuotasResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return QuotasResourceWithStreamingResponse(self) + + def get_all( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> QuotaGetAllResponse: + """Get combined client quotas, including both regional and global quotas.""" + return self._get( + "/cloud/v2/client_quotas", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=QuotaGetAllResponse, + ) + + def get_by_region( + self, + *, + client_id: int, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> QuotaGetByRegionResponse: + """ + Get quotas for a specific region and client. + + Args: + client_id: Client ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v2/regional_quotas/{client_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=QuotaGetByRegionResponse, + ) + + def get_global( + self, + client_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> QuotaGetGlobalResponse: + """ + Get global quotas for a specific client. + + Args: + client_id: Client ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cloud/v2/global_quotas/{client_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=QuotaGetGlobalResponse, + ) + + +class AsyncQuotasResource(AsyncAPIResource): + @cached_property + def requests(self) -> AsyncRequestsResource: + return AsyncRequestsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncQuotasResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncQuotasResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncQuotasResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncQuotasResourceWithStreamingResponse(self) + + async def get_all( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> QuotaGetAllResponse: + """Get combined client quotas, including both regional and global quotas.""" + return await self._get( + "/cloud/v2/client_quotas", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=QuotaGetAllResponse, + ) + + async def get_by_region( + self, + *, + client_id: int, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> QuotaGetByRegionResponse: + """ + Get quotas for a specific region and client. + + Args: + client_id: Client ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v2/regional_quotas/{client_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=QuotaGetByRegionResponse, + ) + + async def get_global( + self, + client_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> QuotaGetGlobalResponse: + """ + Get global quotas for a specific client. + + Args: + client_id: Client ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cloud/v2/global_quotas/{client_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=QuotaGetGlobalResponse, + ) + + +class QuotasResourceWithRawResponse: + def __init__(self, quotas: QuotasResource) -> None: + self._quotas = quotas + + self.get_all = to_raw_response_wrapper( + quotas.get_all, + ) + self.get_by_region = to_raw_response_wrapper( + quotas.get_by_region, + ) + self.get_global = to_raw_response_wrapper( + quotas.get_global, + ) + + @cached_property + def requests(self) -> RequestsResourceWithRawResponse: + return RequestsResourceWithRawResponse(self._quotas.requests) + + +class AsyncQuotasResourceWithRawResponse: + def __init__(self, quotas: AsyncQuotasResource) -> None: + self._quotas = quotas + + self.get_all = async_to_raw_response_wrapper( + quotas.get_all, + ) + self.get_by_region = async_to_raw_response_wrapper( + quotas.get_by_region, + ) + self.get_global = async_to_raw_response_wrapper( + quotas.get_global, + ) + + @cached_property + def requests(self) -> AsyncRequestsResourceWithRawResponse: + return AsyncRequestsResourceWithRawResponse(self._quotas.requests) + + +class QuotasResourceWithStreamingResponse: + def __init__(self, quotas: QuotasResource) -> None: + self._quotas = quotas + + self.get_all = to_streamed_response_wrapper( + quotas.get_all, + ) + self.get_by_region = to_streamed_response_wrapper( + quotas.get_by_region, + ) + self.get_global = to_streamed_response_wrapper( + quotas.get_global, + ) + + @cached_property + def requests(self) -> RequestsResourceWithStreamingResponse: + return RequestsResourceWithStreamingResponse(self._quotas.requests) + + +class AsyncQuotasResourceWithStreamingResponse: + def __init__(self, quotas: AsyncQuotasResource) -> None: + self._quotas = quotas + + self.get_all = async_to_streamed_response_wrapper( + quotas.get_all, + ) + self.get_by_region = async_to_streamed_response_wrapper( + quotas.get_by_region, + ) + self.get_global = async_to_streamed_response_wrapper( + quotas.get_global, + ) + + @cached_property + def requests(self) -> AsyncRequestsResourceWithStreamingResponse: + return AsyncRequestsResourceWithStreamingResponse(self._quotas.requests) diff --git a/src/gcore/resources/cloud/quotas/requests.py b/src/gcore/resources/cloud/quotas/requests.py new file mode 100644 index 00000000..5a12175b --- /dev/null +++ b/src/gcore/resources/cloud/quotas/requests.py @@ -0,0 +1,491 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.quotas import request_list_params, request_create_params +from ....types.cloud.quotas.request_get_response import RequestGetResponse +from ....types.cloud.quotas.request_list_response import RequestListResponse + +__all__ = ["RequestsResource", "AsyncRequestsResource"] + + +class RequestsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RequestsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return RequestsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RequestsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return RequestsResourceWithStreamingResponse(self) + + def create( + self, + *, + description: str, + requested_limits: request_create_params.RequestedLimits, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Create a request to change current quotas. + + Args: + description: Describe the reason, in general terms. + + requested_limits: Limits you want to increase. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + "/cloud/v2/limits_request", + body=maybe_transform( + { + "description": description, + "requested_limits": requested_limits, + }, + request_create_params.RequestCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + *, + created_from: Union[str, datetime] | Omit = omit, + created_to: Union[str, datetime] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + request_ids: Iterable[int] | Omit = omit, + status: List[Literal["done", "in progress", "rejected"]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[RequestListResponse]: + """ + Get a list of sent requests to change current quotas and their statuses. + + Args: + created_from: Filter limit requests created at or after this datetime (inclusive) + + created_to: Filter limit requests created at or before this datetime (inclusive) + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + request_ids: List of limit request IDs for filtering + + status: List of limit requests statuses for filtering + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v2/limits_request", + page=SyncOffsetPage[RequestListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "created_from": created_from, + "created_to": created_to, + "limit": limit, + "offset": offset, + "request_ids": request_ids, + "status": status, + }, + request_list_params.RequestListParams, + ), + ), + model=RequestListResponse, + ) + + def delete( + self, + request_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific quota limit request. + + Args: + request_id: LimitRequest ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v2/limits_request/{request_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + request_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RequestGetResponse: + """ + Get detailed information about a specific quota limit request. + + Args: + request_id: LimitRequest ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/cloud/v2/limits_request/{request_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RequestGetResponse, + ) + + +class AsyncRequestsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRequestsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncRequestsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRequestsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncRequestsResourceWithStreamingResponse(self) + + async def create( + self, + *, + description: str, + requested_limits: request_create_params.RequestedLimits, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Create a request to change current quotas. + + Args: + description: Describe the reason, in general terms. + + requested_limits: Limits you want to increase. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + "/cloud/v2/limits_request", + body=await async_maybe_transform( + { + "description": description, + "requested_limits": requested_limits, + }, + request_create_params.RequestCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + *, + created_from: Union[str, datetime] | Omit = omit, + created_to: Union[str, datetime] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + request_ids: Iterable[int] | Omit = omit, + status: List[Literal["done", "in progress", "rejected"]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[RequestListResponse, AsyncOffsetPage[RequestListResponse]]: + """ + Get a list of sent requests to change current quotas and their statuses. + + Args: + created_from: Filter limit requests created at or after this datetime (inclusive) + + created_to: Filter limit requests created at or before this datetime (inclusive) + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + request_ids: List of limit request IDs for filtering + + status: List of limit requests statuses for filtering + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v2/limits_request", + page=AsyncOffsetPage[RequestListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "created_from": created_from, + "created_to": created_to, + "limit": limit, + "offset": offset, + "request_ids": request_ids, + "status": status, + }, + request_list_params.RequestListParams, + ), + ), + model=RequestListResponse, + ) + + async def delete( + self, + request_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific quota limit request. + + Args: + request_id: LimitRequest ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v2/limits_request/{request_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + request_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RequestGetResponse: + """ + Get detailed information about a specific quota limit request. + + Args: + request_id: LimitRequest ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/cloud/v2/limits_request/{request_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RequestGetResponse, + ) + + +class RequestsResourceWithRawResponse: + def __init__(self, requests: RequestsResource) -> None: + self._requests = requests + + self.create = to_raw_response_wrapper( + requests.create, + ) + self.list = to_raw_response_wrapper( + requests.list, + ) + self.delete = to_raw_response_wrapper( + requests.delete, + ) + self.get = to_raw_response_wrapper( + requests.get, + ) + + +class AsyncRequestsResourceWithRawResponse: + def __init__(self, requests: AsyncRequestsResource) -> None: + self._requests = requests + + self.create = async_to_raw_response_wrapper( + requests.create, + ) + self.list = async_to_raw_response_wrapper( + requests.list, + ) + self.delete = async_to_raw_response_wrapper( + requests.delete, + ) + self.get = async_to_raw_response_wrapper( + requests.get, + ) + + +class RequestsResourceWithStreamingResponse: + def __init__(self, requests: RequestsResource) -> None: + self._requests = requests + + self.create = to_streamed_response_wrapper( + requests.create, + ) + self.list = to_streamed_response_wrapper( + requests.list, + ) + self.delete = to_streamed_response_wrapper( + requests.delete, + ) + self.get = to_streamed_response_wrapper( + requests.get, + ) + + +class AsyncRequestsResourceWithStreamingResponse: + def __init__(self, requests: AsyncRequestsResource) -> None: + self._requests = requests + + self.create = async_to_streamed_response_wrapper( + requests.create, + ) + self.list = async_to_streamed_response_wrapper( + requests.list, + ) + self.delete = async_to_streamed_response_wrapper( + requests.delete, + ) + self.get = async_to_streamed_response_wrapper( + requests.get, + ) diff --git a/src/gcore/resources/cloud/regions.py b/src/gcore/resources/cloud/regions.py new file mode 100644 index 00000000..b9d06835 --- /dev/null +++ b/src/gcore/resources/cloud/regions.py @@ -0,0 +1,326 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ...types.cloud import region_get_params, region_list_params +from ..._base_client import AsyncPaginator, make_request_options +from ...types.cloud.region import Region + +__all__ = ["RegionsResource", "AsyncRegionsResource"] + + +class RegionsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RegionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return RegionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RegionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return RegionsResourceWithStreamingResponse(self) + + def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["created_at.asc", "created_at.desc", "display_name.asc", "display_name.desc"] | Omit = omit, + product: Literal["containers", "inference"] | Omit = omit, + show_volume_types: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[Region]: + """List regions + + Args: + limit: Limit the number of returned regions. + + Falls back to default of 100 if not + specified. Limited by max limit value of 1000 + + offset: Offset value is used to exclude the first set of records from the result + + order_by: Order by field and direction. + + product: If defined then return only regions that support given product. + + show_volume_types: If true, null `available_volume_type` is replaced with a list of available + volume types. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v1/regions", + page=SyncOffsetPage[Region], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + "order_by": order_by, + "product": product, + "show_volume_types": show_volume_types, + }, + region_list_params.RegionListParams, + ), + ), + model=Region, + ) + + def get( + self, + *, + region_id: int | None = None, + show_volume_types: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Region: + """ + Get region + + Args: + region_id: Region ID + + show_volume_types: If true, null `available_volume_type` is replaced with a list of available + volume types. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/regions/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"show_volume_types": show_volume_types}, region_get_params.RegionGetParams), + ), + cast_to=Region, + ) + + +class AsyncRegionsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRegionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncRegionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRegionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncRegionsResourceWithStreamingResponse(self) + + def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["created_at.asc", "created_at.desc", "display_name.asc", "display_name.desc"] | Omit = omit, + product: Literal["containers", "inference"] | Omit = omit, + show_volume_types: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Region, AsyncOffsetPage[Region]]: + """List regions + + Args: + limit: Limit the number of returned regions. + + Falls back to default of 100 if not + specified. Limited by max limit value of 1000 + + offset: Offset value is used to exclude the first set of records from the result + + order_by: Order by field and direction. + + product: If defined then return only regions that support given product. + + show_volume_types: If true, null `available_volume_type` is replaced with a list of available + volume types. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v1/regions", + page=AsyncOffsetPage[Region], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + "order_by": order_by, + "product": product, + "show_volume_types": show_volume_types, + }, + region_list_params.RegionListParams, + ), + ), + model=Region, + ) + + async def get( + self, + *, + region_id: int | None = None, + show_volume_types: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Region: + """ + Get region + + Args: + region_id: Region ID + + show_volume_types: If true, null `available_volume_type` is replaced with a list of available + volume types. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/regions/{region_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"show_volume_types": show_volume_types}, region_get_params.RegionGetParams + ), + ), + cast_to=Region, + ) + + +class RegionsResourceWithRawResponse: + def __init__(self, regions: RegionsResource) -> None: + self._regions = regions + + self.list = to_raw_response_wrapper( + regions.list, + ) + self.get = to_raw_response_wrapper( + regions.get, + ) + + +class AsyncRegionsResourceWithRawResponse: + def __init__(self, regions: AsyncRegionsResource) -> None: + self._regions = regions + + self.list = async_to_raw_response_wrapper( + regions.list, + ) + self.get = async_to_raw_response_wrapper( + regions.get, + ) + + +class RegionsResourceWithStreamingResponse: + def __init__(self, regions: RegionsResource) -> None: + self._regions = regions + + self.list = to_streamed_response_wrapper( + regions.list, + ) + self.get = to_streamed_response_wrapper( + regions.get, + ) + + +class AsyncRegionsResourceWithStreamingResponse: + def __init__(self, regions: AsyncRegionsResource) -> None: + self._regions = regions + + self.list = async_to_streamed_response_wrapper( + regions.list, + ) + self.get = async_to_streamed_response_wrapper( + regions.get, + ) diff --git a/src/gcore/resources/cloud/registries/__init__.py b/src/gcore/resources/cloud/registries/__init__.py new file mode 100644 index 00000000..92477d1a --- /dev/null +++ b/src/gcore/resources/cloud/registries/__init__.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .tags import ( + TagsResource, + AsyncTagsResource, + TagsResourceWithRawResponse, + AsyncTagsResourceWithRawResponse, + TagsResourceWithStreamingResponse, + AsyncTagsResourceWithStreamingResponse, +) +from .users import ( + UsersResource, + AsyncUsersResource, + UsersResourceWithRawResponse, + AsyncUsersResourceWithRawResponse, + UsersResourceWithStreamingResponse, + AsyncUsersResourceWithStreamingResponse, +) +from .artifacts import ( + ArtifactsResource, + AsyncArtifactsResource, + ArtifactsResourceWithRawResponse, + AsyncArtifactsResourceWithRawResponse, + ArtifactsResourceWithStreamingResponse, + AsyncArtifactsResourceWithStreamingResponse, +) +from .registries import ( + RegistriesResource, + AsyncRegistriesResource, + RegistriesResourceWithRawResponse, + AsyncRegistriesResourceWithRawResponse, + RegistriesResourceWithStreamingResponse, + AsyncRegistriesResourceWithStreamingResponse, +) +from .repositories import ( + RepositoriesResource, + AsyncRepositoriesResource, + RepositoriesResourceWithRawResponse, + AsyncRepositoriesResourceWithRawResponse, + RepositoriesResourceWithStreamingResponse, + AsyncRepositoriesResourceWithStreamingResponse, +) + +__all__ = [ + "RepositoriesResource", + "AsyncRepositoriesResource", + "RepositoriesResourceWithRawResponse", + "AsyncRepositoriesResourceWithRawResponse", + "RepositoriesResourceWithStreamingResponse", + "AsyncRepositoriesResourceWithStreamingResponse", + "ArtifactsResource", + "AsyncArtifactsResource", + "ArtifactsResourceWithRawResponse", + "AsyncArtifactsResourceWithRawResponse", + "ArtifactsResourceWithStreamingResponse", + "AsyncArtifactsResourceWithStreamingResponse", + "TagsResource", + "AsyncTagsResource", + "TagsResourceWithRawResponse", + "AsyncTagsResourceWithRawResponse", + "TagsResourceWithStreamingResponse", + "AsyncTagsResourceWithStreamingResponse", + "UsersResource", + "AsyncUsersResource", + "UsersResourceWithRawResponse", + "AsyncUsersResourceWithRawResponse", + "UsersResourceWithStreamingResponse", + "AsyncUsersResourceWithStreamingResponse", + "RegistriesResource", + "AsyncRegistriesResource", + "RegistriesResourceWithRawResponse", + "AsyncRegistriesResourceWithRawResponse", + "RegistriesResourceWithStreamingResponse", + "AsyncRegistriesResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/registries/artifacts.py b/src/gcore/resources/cloud/registries/artifacts.py new file mode 100644 index 00000000..4b07607a --- /dev/null +++ b/src/gcore/resources/cloud/registries/artifacts.py @@ -0,0 +1,277 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Query, Headers, NoneType, NotGiven, not_given +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.registries.registry_artifact_list import RegistryArtifactList + +__all__ = ["ArtifactsResource", "AsyncArtifactsResource"] + + +class ArtifactsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ArtifactsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ArtifactsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ArtifactsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ArtifactsResourceWithStreamingResponse(self) + + def list( + self, + repository_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryArtifactList: + """ + List all artifacts in a specific repository. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not repository_name: + raise ValueError(f"Expected a non-empty value for `repository_name` but received {repository_name!r}") + return self._get( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/repositories/{repository_name}/artifacts", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryArtifactList, + ) + + def delete( + self, + digest: str, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + repository_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific artifact from a repository. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not repository_name: + raise ValueError(f"Expected a non-empty value for `repository_name` but received {repository_name!r}") + if not digest: + raise ValueError(f"Expected a non-empty value for `digest` but received {digest!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/repositories/{repository_name}/artifacts/{digest}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncArtifactsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncArtifactsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncArtifactsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncArtifactsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncArtifactsResourceWithStreamingResponse(self) + + async def list( + self, + repository_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryArtifactList: + """ + List all artifacts in a specific repository. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not repository_name: + raise ValueError(f"Expected a non-empty value for `repository_name` but received {repository_name!r}") + return await self._get( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/repositories/{repository_name}/artifacts", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryArtifactList, + ) + + async def delete( + self, + digest: str, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + repository_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific artifact from a repository. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not repository_name: + raise ValueError(f"Expected a non-empty value for `repository_name` but received {repository_name!r}") + if not digest: + raise ValueError(f"Expected a non-empty value for `digest` but received {digest!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/repositories/{repository_name}/artifacts/{digest}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class ArtifactsResourceWithRawResponse: + def __init__(self, artifacts: ArtifactsResource) -> None: + self._artifacts = artifacts + + self.list = to_raw_response_wrapper( + artifacts.list, + ) + self.delete = to_raw_response_wrapper( + artifacts.delete, + ) + + +class AsyncArtifactsResourceWithRawResponse: + def __init__(self, artifacts: AsyncArtifactsResource) -> None: + self._artifacts = artifacts + + self.list = async_to_raw_response_wrapper( + artifacts.list, + ) + self.delete = async_to_raw_response_wrapper( + artifacts.delete, + ) + + +class ArtifactsResourceWithStreamingResponse: + def __init__(self, artifacts: ArtifactsResource) -> None: + self._artifacts = artifacts + + self.list = to_streamed_response_wrapper( + artifacts.list, + ) + self.delete = to_streamed_response_wrapper( + artifacts.delete, + ) + + +class AsyncArtifactsResourceWithStreamingResponse: + def __init__(self, artifacts: AsyncArtifactsResource) -> None: + self._artifacts = artifacts + + self.list = async_to_streamed_response_wrapper( + artifacts.list, + ) + self.delete = async_to_streamed_response_wrapper( + artifacts.delete, + ) diff --git a/src/gcore/resources/cloud/registries/registries.py b/src/gcore/resources/cloud/registries/registries.py new file mode 100644 index 00000000..0ba3414e --- /dev/null +++ b/src/gcore/resources/cloud/registries/registries.py @@ -0,0 +1,688 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .tags import ( + TagsResource, + AsyncTagsResource, + TagsResourceWithRawResponse, + AsyncTagsResourceWithRawResponse, + TagsResourceWithStreamingResponse, + AsyncTagsResourceWithStreamingResponse, +) +from .users import ( + UsersResource, + AsyncUsersResource, + UsersResourceWithRawResponse, + AsyncUsersResourceWithRawResponse, + UsersResourceWithStreamingResponse, + AsyncUsersResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from .artifacts import ( + ArtifactsResource, + AsyncArtifactsResource, + ArtifactsResourceWithRawResponse, + AsyncArtifactsResourceWithRawResponse, + ArtifactsResourceWithStreamingResponse, + AsyncArtifactsResourceWithStreamingResponse, +) +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .repositories import ( + RepositoriesResource, + AsyncRepositoriesResource, + RepositoriesResourceWithRawResponse, + AsyncRepositoriesResourceWithRawResponse, + RepositoriesResourceWithStreamingResponse, + AsyncRepositoriesResourceWithStreamingResponse, +) +from ....types.cloud import registry_create_params, registry_resize_params +from ...._base_client import make_request_options +from ....types.cloud.registry import Registry +from ....types.cloud.registry_list import RegistryList + +__all__ = ["RegistriesResource", "AsyncRegistriesResource"] + + +class RegistriesResource(SyncAPIResource): + @cached_property + def repositories(self) -> RepositoriesResource: + return RepositoriesResource(self._client) + + @cached_property + def artifacts(self) -> ArtifactsResource: + return ArtifactsResource(self._client) + + @cached_property + def tags(self) -> TagsResource: + return TagsResource(self._client) + + @cached_property + def users(self) -> UsersResource: + return UsersResource(self._client) + + @cached_property + def with_raw_response(self) -> RegistriesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return RegistriesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RegistriesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return RegistriesResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + storage_limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Registry: + """ + Create a new container registry with the specified configuration. + + Args: + name: A name for the container registry. + + Should be in lowercase, consisting only of numbers, letters and -, + + with maximum length of 24 characters + + storage_limit: Registry storage limit, GiB + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/registries/{project_id}/{region_id}", + body=maybe_transform( + { + "name": name, + "storage_limit": storage_limit, + }, + registry_create_params.RegistryCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Registry, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryList: + """ + List all container registries in the specified project and region. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/registries/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryList, + ) + + def delete( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific container registry and all its associated resources. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Registry: + """ + Get detailed information about a specific container registry. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Registry, + ) + + def resize( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + storage_limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Registry: + """ + Update the size of a container registry. + + Args: + storage_limit: Registry storage limit, GiB + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._patch( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/resize", + body=maybe_transform({"storage_limit": storage_limit}, registry_resize_params.RegistryResizeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Registry, + ) + + +class AsyncRegistriesResource(AsyncAPIResource): + @cached_property + def repositories(self) -> AsyncRepositoriesResource: + return AsyncRepositoriesResource(self._client) + + @cached_property + def artifacts(self) -> AsyncArtifactsResource: + return AsyncArtifactsResource(self._client) + + @cached_property + def tags(self) -> AsyncTagsResource: + return AsyncTagsResource(self._client) + + @cached_property + def users(self) -> AsyncUsersResource: + return AsyncUsersResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncRegistriesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncRegistriesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRegistriesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncRegistriesResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + storage_limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Registry: + """ + Create a new container registry with the specified configuration. + + Args: + name: A name for the container registry. + + Should be in lowercase, consisting only of numbers, letters and -, + + with maximum length of 24 characters + + storage_limit: Registry storage limit, GiB + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/registries/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "name": name, + "storage_limit": storage_limit, + }, + registry_create_params.RegistryCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Registry, + ) + + async def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryList: + """ + List all container registries in the specified project and region. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/registries/{project_id}/{region_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryList, + ) + + async def delete( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific container registry and all its associated resources. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Registry: + """ + Get detailed information about a specific container registry. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Registry, + ) + + async def resize( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + storage_limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Registry: + """ + Update the size of a container registry. + + Args: + storage_limit: Registry storage limit, GiB + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._patch( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/resize", + body=await async_maybe_transform( + {"storage_limit": storage_limit}, registry_resize_params.RegistryResizeParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Registry, + ) + + +class RegistriesResourceWithRawResponse: + def __init__(self, registries: RegistriesResource) -> None: + self._registries = registries + + self.create = to_raw_response_wrapper( + registries.create, + ) + self.list = to_raw_response_wrapper( + registries.list, + ) + self.delete = to_raw_response_wrapper( + registries.delete, + ) + self.get = to_raw_response_wrapper( + registries.get, + ) + self.resize = to_raw_response_wrapper( + registries.resize, + ) + + @cached_property + def repositories(self) -> RepositoriesResourceWithRawResponse: + return RepositoriesResourceWithRawResponse(self._registries.repositories) + + @cached_property + def artifacts(self) -> ArtifactsResourceWithRawResponse: + return ArtifactsResourceWithRawResponse(self._registries.artifacts) + + @cached_property + def tags(self) -> TagsResourceWithRawResponse: + return TagsResourceWithRawResponse(self._registries.tags) + + @cached_property + def users(self) -> UsersResourceWithRawResponse: + return UsersResourceWithRawResponse(self._registries.users) + + +class AsyncRegistriesResourceWithRawResponse: + def __init__(self, registries: AsyncRegistriesResource) -> None: + self._registries = registries + + self.create = async_to_raw_response_wrapper( + registries.create, + ) + self.list = async_to_raw_response_wrapper( + registries.list, + ) + self.delete = async_to_raw_response_wrapper( + registries.delete, + ) + self.get = async_to_raw_response_wrapper( + registries.get, + ) + self.resize = async_to_raw_response_wrapper( + registries.resize, + ) + + @cached_property + def repositories(self) -> AsyncRepositoriesResourceWithRawResponse: + return AsyncRepositoriesResourceWithRawResponse(self._registries.repositories) + + @cached_property + def artifacts(self) -> AsyncArtifactsResourceWithRawResponse: + return AsyncArtifactsResourceWithRawResponse(self._registries.artifacts) + + @cached_property + def tags(self) -> AsyncTagsResourceWithRawResponse: + return AsyncTagsResourceWithRawResponse(self._registries.tags) + + @cached_property + def users(self) -> AsyncUsersResourceWithRawResponse: + return AsyncUsersResourceWithRawResponse(self._registries.users) + + +class RegistriesResourceWithStreamingResponse: + def __init__(self, registries: RegistriesResource) -> None: + self._registries = registries + + self.create = to_streamed_response_wrapper( + registries.create, + ) + self.list = to_streamed_response_wrapper( + registries.list, + ) + self.delete = to_streamed_response_wrapper( + registries.delete, + ) + self.get = to_streamed_response_wrapper( + registries.get, + ) + self.resize = to_streamed_response_wrapper( + registries.resize, + ) + + @cached_property + def repositories(self) -> RepositoriesResourceWithStreamingResponse: + return RepositoriesResourceWithStreamingResponse(self._registries.repositories) + + @cached_property + def artifacts(self) -> ArtifactsResourceWithStreamingResponse: + return ArtifactsResourceWithStreamingResponse(self._registries.artifacts) + + @cached_property + def tags(self) -> TagsResourceWithStreamingResponse: + return TagsResourceWithStreamingResponse(self._registries.tags) + + @cached_property + def users(self) -> UsersResourceWithStreamingResponse: + return UsersResourceWithStreamingResponse(self._registries.users) + + +class AsyncRegistriesResourceWithStreamingResponse: + def __init__(self, registries: AsyncRegistriesResource) -> None: + self._registries = registries + + self.create = async_to_streamed_response_wrapper( + registries.create, + ) + self.list = async_to_streamed_response_wrapper( + registries.list, + ) + self.delete = async_to_streamed_response_wrapper( + registries.delete, + ) + self.get = async_to_streamed_response_wrapper( + registries.get, + ) + self.resize = async_to_streamed_response_wrapper( + registries.resize, + ) + + @cached_property + def repositories(self) -> AsyncRepositoriesResourceWithStreamingResponse: + return AsyncRepositoriesResourceWithStreamingResponse(self._registries.repositories) + + @cached_property + def artifacts(self) -> AsyncArtifactsResourceWithStreamingResponse: + return AsyncArtifactsResourceWithStreamingResponse(self._registries.artifacts) + + @cached_property + def tags(self) -> AsyncTagsResourceWithStreamingResponse: + return AsyncTagsResourceWithStreamingResponse(self._registries.tags) + + @cached_property + def users(self) -> AsyncUsersResourceWithStreamingResponse: + return AsyncUsersResourceWithStreamingResponse(self._registries.users) diff --git a/src/gcore/resources/cloud/registries/repositories.py b/src/gcore/resources/cloud/registries/repositories.py new file mode 100644 index 00000000..d0c860a9 --- /dev/null +++ b/src/gcore/resources/cloud/registries/repositories.py @@ -0,0 +1,265 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Query, Headers, NoneType, NotGiven, not_given +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.registries.registry_repository_list import RegistryRepositoryList + +__all__ = ["RepositoriesResource", "AsyncRepositoriesResource"] + + +class RepositoriesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RepositoriesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return RepositoriesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RepositoriesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return RepositoriesResourceWithStreamingResponse(self) + + def list( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryRepositoryList: + """ + List all repositories in the container registry. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/repositories", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryRepositoryList, + ) + + def delete( + self, + repository_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific repository from the container registry. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not repository_name: + raise ValueError(f"Expected a non-empty value for `repository_name` but received {repository_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/repositories/{repository_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncRepositoriesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRepositoriesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncRepositoriesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRepositoriesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncRepositoriesResourceWithStreamingResponse(self) + + async def list( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryRepositoryList: + """ + List all repositories in the container registry. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/repositories", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryRepositoryList, + ) + + async def delete( + self, + repository_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific repository from the container registry. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not repository_name: + raise ValueError(f"Expected a non-empty value for `repository_name` but received {repository_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/repositories/{repository_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class RepositoriesResourceWithRawResponse: + def __init__(self, repositories: RepositoriesResource) -> None: + self._repositories = repositories + + self.list = to_raw_response_wrapper( + repositories.list, + ) + self.delete = to_raw_response_wrapper( + repositories.delete, + ) + + +class AsyncRepositoriesResourceWithRawResponse: + def __init__(self, repositories: AsyncRepositoriesResource) -> None: + self._repositories = repositories + + self.list = async_to_raw_response_wrapper( + repositories.list, + ) + self.delete = async_to_raw_response_wrapper( + repositories.delete, + ) + + +class RepositoriesResourceWithStreamingResponse: + def __init__(self, repositories: RepositoriesResource) -> None: + self._repositories = repositories + + self.list = to_streamed_response_wrapper( + repositories.list, + ) + self.delete = to_streamed_response_wrapper( + repositories.delete, + ) + + +class AsyncRepositoriesResourceWithStreamingResponse: + def __init__(self, repositories: AsyncRepositoriesResource) -> None: + self._repositories = repositories + + self.list = async_to_streamed_response_wrapper( + repositories.list, + ) + self.delete = async_to_streamed_response_wrapper( + repositories.delete, + ) diff --git a/src/gcore/resources/cloud/registries/tags.py b/src/gcore/resources/cloud/registries/tags.py new file mode 100644 index 00000000..74f68017 --- /dev/null +++ b/src/gcore/resources/cloud/registries/tags.py @@ -0,0 +1,190 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Query, Headers, NoneType, NotGiven, not_given +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options + +__all__ = ["TagsResource", "AsyncTagsResource"] + + +class TagsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> TagsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return TagsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TagsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return TagsResourceWithStreamingResponse(self) + + def delete( + self, + tag_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + repository_name: str, + digest: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific tag from an artifact. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not repository_name: + raise ValueError(f"Expected a non-empty value for `repository_name` but received {repository_name!r}") + if not digest: + raise ValueError(f"Expected a non-empty value for `digest` but received {digest!r}") + if not tag_name: + raise ValueError(f"Expected a non-empty value for `tag_name` but received {tag_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/repositories/{repository_name}/artifacts/{digest}/tags/{tag_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncTagsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncTagsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncTagsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTagsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncTagsResourceWithStreamingResponse(self) + + async def delete( + self, + tag_name: str, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + repository_name: str, + digest: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific tag from an artifact. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not repository_name: + raise ValueError(f"Expected a non-empty value for `repository_name` but received {repository_name!r}") + if not digest: + raise ValueError(f"Expected a non-empty value for `digest` but received {digest!r}") + if not tag_name: + raise ValueError(f"Expected a non-empty value for `tag_name` but received {tag_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/repositories/{repository_name}/artifacts/{digest}/tags/{tag_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class TagsResourceWithRawResponse: + def __init__(self, tags: TagsResource) -> None: + self._tags = tags + + self.delete = to_raw_response_wrapper( + tags.delete, + ) + + +class AsyncTagsResourceWithRawResponse: + def __init__(self, tags: AsyncTagsResource) -> None: + self._tags = tags + + self.delete = async_to_raw_response_wrapper( + tags.delete, + ) + + +class TagsResourceWithStreamingResponse: + def __init__(self, tags: TagsResource) -> None: + self._tags = tags + + self.delete = to_streamed_response_wrapper( + tags.delete, + ) + + +class AsyncTagsResourceWithStreamingResponse: + def __init__(self, tags: AsyncTagsResource) -> None: + self._tags = tags + + self.delete = async_to_streamed_response_wrapper( + tags.delete, + ) diff --git a/src/gcore/resources/cloud/registries/users.py b/src/gcore/resources/cloud/registries/users.py new file mode 100644 index 00000000..5225429a --- /dev/null +++ b/src/gcore/resources/cloud/registries/users.py @@ -0,0 +1,700 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.registries import user_create_params, user_update_params, user_create_multiple_params +from ....types.cloud.registries.registry_user import RegistryUser +from ....types.cloud.registries.registry_user_list import RegistryUserList +from ....types.cloud.registries.registry_user_created import RegistryUserCreated +from ....types.cloud.registries.user_refresh_secret_response import UserRefreshSecretResponse + +__all__ = ["UsersResource", "AsyncUsersResource"] + + +class UsersResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> UsersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return UsersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> UsersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return UsersResourceWithStreamingResponse(self) + + def create( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + duration: int, + name: str, + read_only: bool | Omit = omit, + secret: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryUserCreated: + """ + Create a new user for accessing the container registry. + + Args: + duration: User account operating time, days + + name: A name for the registry user. + + Should be in lowercase, consisting only of numbers and letters, + + with maximum length of 16 characters + + read_only: Read-only user + + secret: User secret + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/users", + body=maybe_transform( + { + "duration": duration, + "name": name, + "read_only": read_only, + "secret": secret, + }, + user_create_params.UserCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryUserCreated, + ) + + def update( + self, + user_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + duration: int, + read_only: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryUser: + """ + Update the configuration of a specific registry user. + + Args: + duration: User account operating time, days + + read_only: Read-only user + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._patch( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/users/{user_id}", + body=maybe_transform( + { + "duration": duration, + "read_only": read_only, + }, + user_update_params.UserUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryUser, + ) + + def list( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryUserList: + """ + List all users with access to the container registry. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/users", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryUserList, + ) + + def delete( + self, + user_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific user from the container registry. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/users/{user_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def create_multiple( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + users: Iterable[user_create_multiple_params.User], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryUserCreated: + """ + Create multiple users for accessing the container registry in a single request. + + Args: + users: Set of users + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/users/batch", + body=maybe_transform({"users": users}, user_create_multiple_params.UserCreateMultipleParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryUserCreated, + ) + + def refresh_secret( + self, + user_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserRefreshSecretResponse: + """ + Generate a new secret for a specific registry user. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/users/{user_id}/refresh_secret", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UserRefreshSecretResponse, + ) + + +class AsyncUsersResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncUsersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncUsersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncUsersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncUsersResourceWithStreamingResponse(self) + + async def create( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + duration: int, + name: str, + read_only: bool | Omit = omit, + secret: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryUserCreated: + """ + Create a new user for accessing the container registry. + + Args: + duration: User account operating time, days + + name: A name for the registry user. + + Should be in lowercase, consisting only of numbers and letters, + + with maximum length of 16 characters + + read_only: Read-only user + + secret: User secret + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/users", + body=await async_maybe_transform( + { + "duration": duration, + "name": name, + "read_only": read_only, + "secret": secret, + }, + user_create_params.UserCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryUserCreated, + ) + + async def update( + self, + user_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + duration: int, + read_only: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryUser: + """ + Update the configuration of a specific registry user. + + Args: + duration: User account operating time, days + + read_only: Read-only user + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._patch( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/users/{user_id}", + body=await async_maybe_transform( + { + "duration": duration, + "read_only": read_only, + }, + user_update_params.UserUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryUser, + ) + + async def list( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryUserList: + """ + List all users with access to the container registry. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._get( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/users", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryUserList, + ) + + async def delete( + self, + user_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific user from the container registry. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/users/{user_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def create_multiple( + self, + registry_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + users: Iterable[user_create_multiple_params.User], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RegistryUserCreated: + """ + Create multiple users for accessing the container registry in a single request. + + Args: + users: Set of users + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/users/batch", + body=await async_maybe_transform({"users": users}, user_create_multiple_params.UserCreateMultipleParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RegistryUserCreated, + ) + + async def refresh_secret( + self, + user_id: int, + *, + project_id: int | None = None, + region_id: int | None = None, + registry_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserRefreshSecretResponse: + """ + Generate a new secret for a specific registry user. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/registries/{project_id}/{region_id}/{registry_id}/users/{user_id}/refresh_secret", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UserRefreshSecretResponse, + ) + + +class UsersResourceWithRawResponse: + def __init__(self, users: UsersResource) -> None: + self._users = users + + self.create = to_raw_response_wrapper( + users.create, + ) + self.update = to_raw_response_wrapper( + users.update, + ) + self.list = to_raw_response_wrapper( + users.list, + ) + self.delete = to_raw_response_wrapper( + users.delete, + ) + self.create_multiple = to_raw_response_wrapper( + users.create_multiple, + ) + self.refresh_secret = to_raw_response_wrapper( + users.refresh_secret, + ) + + +class AsyncUsersResourceWithRawResponse: + def __init__(self, users: AsyncUsersResource) -> None: + self._users = users + + self.create = async_to_raw_response_wrapper( + users.create, + ) + self.update = async_to_raw_response_wrapper( + users.update, + ) + self.list = async_to_raw_response_wrapper( + users.list, + ) + self.delete = async_to_raw_response_wrapper( + users.delete, + ) + self.create_multiple = async_to_raw_response_wrapper( + users.create_multiple, + ) + self.refresh_secret = async_to_raw_response_wrapper( + users.refresh_secret, + ) + + +class UsersResourceWithStreamingResponse: + def __init__(self, users: UsersResource) -> None: + self._users = users + + self.create = to_streamed_response_wrapper( + users.create, + ) + self.update = to_streamed_response_wrapper( + users.update, + ) + self.list = to_streamed_response_wrapper( + users.list, + ) + self.delete = to_streamed_response_wrapper( + users.delete, + ) + self.create_multiple = to_streamed_response_wrapper( + users.create_multiple, + ) + self.refresh_secret = to_streamed_response_wrapper( + users.refresh_secret, + ) + + +class AsyncUsersResourceWithStreamingResponse: + def __init__(self, users: AsyncUsersResource) -> None: + self._users = users + + self.create = async_to_streamed_response_wrapper( + users.create, + ) + self.update = async_to_streamed_response_wrapper( + users.update, + ) + self.list = async_to_streamed_response_wrapper( + users.list, + ) + self.delete = async_to_streamed_response_wrapper( + users.delete, + ) + self.create_multiple = async_to_streamed_response_wrapper( + users.create_multiple, + ) + self.refresh_secret = async_to_streamed_response_wrapper( + users.refresh_secret, + ) diff --git a/src/gcore/resources/cloud/reserved_fixed_ips/__init__.py b/src/gcore/resources/cloud/reserved_fixed_ips/__init__.py new file mode 100644 index 00000000..efec3183 --- /dev/null +++ b/src/gcore/resources/cloud/reserved_fixed_ips/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .vip import ( + VipResource, + AsyncVipResource, + VipResourceWithRawResponse, + AsyncVipResourceWithRawResponse, + VipResourceWithStreamingResponse, + AsyncVipResourceWithStreamingResponse, +) +from .reserved_fixed_ips import ( + ReservedFixedIPsResource, + AsyncReservedFixedIPsResource, + ReservedFixedIPsResourceWithRawResponse, + AsyncReservedFixedIPsResourceWithRawResponse, + ReservedFixedIPsResourceWithStreamingResponse, + AsyncReservedFixedIPsResourceWithStreamingResponse, +) + +__all__ = [ + "VipResource", + "AsyncVipResource", + "VipResourceWithRawResponse", + "AsyncVipResourceWithRawResponse", + "VipResourceWithStreamingResponse", + "AsyncVipResourceWithStreamingResponse", + "ReservedFixedIPsResource", + "AsyncReservedFixedIPsResource", + "ReservedFixedIPsResourceWithRawResponse", + "AsyncReservedFixedIPsResourceWithRawResponse", + "ReservedFixedIPsResourceWithStreamingResponse", + "AsyncReservedFixedIPsResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/reserved_fixed_ips/reserved_fixed_ips.py b/src/gcore/resources/cloud/reserved_fixed_ips/reserved_fixed_ips.py new file mode 100644 index 00000000..3dd9e402 --- /dev/null +++ b/src/gcore/resources/cloud/reserved_fixed_ips/reserved_fixed_ips.py @@ -0,0 +1,1070 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, overload + +import httpx + +from .vip.vip import ( + VipResource, + AsyncVipResource, + VipResourceWithRawResponse, + AsyncVipResourceWithRawResponse, + VipResourceWithStreamingResponse, + AsyncVipResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import required_args, maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ....types.cloud import ( + InterfaceIPFamily, + reserved_fixed_ip_list_params, + reserved_fixed_ip_create_params, + reserved_fixed_ip_update_params, +) +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.task_id_list import TaskIDList +from ....types.cloud.reserved_fixed_ip import ReservedFixedIP +from ....types.cloud.interface_ip_family import InterfaceIPFamily + +__all__ = ["ReservedFixedIPsResource", "AsyncReservedFixedIPsResource"] + + +class ReservedFixedIPsResource(SyncAPIResource): + @cached_property + def vip(self) -> VipResource: + return VipResource(self._client) + + @cached_property + def with_raw_response(self) -> ReservedFixedIPsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ReservedFixedIPsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ReservedFixedIPsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ReservedFixedIPsResourceWithStreamingResponse(self) + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + type: Literal["external"], + ip_family: Optional[InterfaceIPFamily] | Omit = omit, + is_vip: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new reserved fixed IP with the specified configuration. + + Args: + type: Must be 'external' + + ip_family: Which subnets should be selected: IPv4, IPv6 or use dual stack. + + is_vip: If reserved fixed IP is a VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + subnet_id: str, + type: Literal["subnet"], + is_vip: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new reserved fixed IP with the specified configuration. + + Args: + subnet_id: Reserved fixed IP will be allocated in this subnet + + type: Must be 'subnet'. + + is_vip: If reserved fixed IP is a VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + network_id: str, + type: Literal["any_subnet"], + ip_family: Optional[InterfaceIPFamily] | Omit = omit, + is_vip: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new reserved fixed IP with the specified configuration. + + Args: + network_id: Reserved fixed IP will be allocated in a subnet of this network + + type: Must be 'any_subnet'. + + ip_family: Which subnets should be selected: IPv4, IPv6 or use dual stack. + + is_vip: If reserved fixed IP is a VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + ip_address: str, + network_id: str, + type: Literal["ip_address"], + is_vip: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new reserved fixed IP with the specified configuration. + + Args: + ip_address: Reserved fixed IP will be allocated the given IP address + + network_id: Reserved fixed IP will be allocated in a subnet of this network + + type: Must be 'ip_address'. + + is_vip: If reserved fixed IP is a VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + port_id: str, + type: Literal["port"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new reserved fixed IP with the specified configuration. + + Args: + port_id: Port ID to make a reserved fixed IP (for example, `vip_port_id` of the Load + Balancer entity). + + type: Must be 'port'. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args( + ["type"], + ["subnet_id", "type"], + ["network_id", "type"], + ["ip_address", "network_id", "type"], + ["port_id", "type"], + ) + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + type: Literal["external"] | Literal["subnet"] | Literal["any_subnet"] | Literal["ip_address"] | Literal["port"], + ip_family: Optional[InterfaceIPFamily] | Omit = omit, + is_vip: bool | Omit = omit, + subnet_id: str | Omit = omit, + network_id: str | Omit = omit, + ip_address: str | Omit = omit, + port_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}", + body=maybe_transform( + { + "type": type, + "ip_family": ip_family, + "is_vip": is_vip, + "subnet_id": subnet_id, + "network_id": network_id, + "ip_address": ip_address, + "port_id": port_id, + }, + reserved_fixed_ip_create_params.ReservedFixedIPCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + is_vip: bool, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ReservedFixedIP: + """ + Update the VIP status of a reserved fixed IP. + + Args: + is_vip: If reserved fixed IP should be a VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return self._patch( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}", + body=maybe_transform({"is_vip": is_vip}, reserved_fixed_ip_update_params.ReservedFixedIPUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ReservedFixedIP, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + available_only: bool | Omit = omit, + device_id: str | Omit = omit, + external_only: bool | Omit = omit, + internal_only: bool | Omit = omit, + ip_address: str | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: str | Omit = omit, + vip_only: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[ReservedFixedIP]: + """ + List all reserved fixed IPs in the specified project and region. + + Args: + available_only: Set to true if the response should only list IP addresses that are not attached + to any instance + + device_id: Filter IPs by device ID it is attached to + + external_only: Set to true if the response should only list public IP addresses + + internal_only: Set to true if the response should only list private IP addresses + + ip_address: An IPv4 address to filter results by. Regular expression allowed + + limit: Limit the number of returned IPs + + offset: Offset value is used to exclude the first set of records from the result + + order_by: Ordering reserved fixed IP list result by name, status, `updated_at`, + `created_at` or `fixed_ip_address` fields and directions (status.asc), default + is "fixed_ip_address.asc" + + vip_only: Set to true if the response should only list VIPs + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}", + page=SyncOffsetPage[ReservedFixedIP], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "available_only": available_only, + "device_id": device_id, + "external_only": external_only, + "internal_only": internal_only, + "ip_address": ip_address, + "limit": limit, + "offset": offset, + "order_by": order_by, + "vip_only": vip_only, + }, + reserved_fixed_ip_list_params.ReservedFixedIPListParams, + ), + ), + model=ReservedFixedIP, + ) + + def delete( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a specific reserved fixed IP and all its associated resources. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return self._delete( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ReservedFixedIP: + """ + Get detailed information about a specific reserved fixed IP. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return self._get( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ReservedFixedIP, + ) + + +class AsyncReservedFixedIPsResource(AsyncAPIResource): + @cached_property + def vip(self) -> AsyncVipResource: + return AsyncVipResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncReservedFixedIPsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncReservedFixedIPsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncReservedFixedIPsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncReservedFixedIPsResourceWithStreamingResponse(self) + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + type: Literal["external"], + ip_family: Optional[InterfaceIPFamily] | Omit = omit, + is_vip: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new reserved fixed IP with the specified configuration. + + Args: + type: Must be 'external' + + ip_family: Which subnets should be selected: IPv4, IPv6 or use dual stack. + + is_vip: If reserved fixed IP is a VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + subnet_id: str, + type: Literal["subnet"], + is_vip: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new reserved fixed IP with the specified configuration. + + Args: + subnet_id: Reserved fixed IP will be allocated in this subnet + + type: Must be 'subnet'. + + is_vip: If reserved fixed IP is a VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + network_id: str, + type: Literal["any_subnet"], + ip_family: Optional[InterfaceIPFamily] | Omit = omit, + is_vip: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new reserved fixed IP with the specified configuration. + + Args: + network_id: Reserved fixed IP will be allocated in a subnet of this network + + type: Must be 'any_subnet'. + + ip_family: Which subnets should be selected: IPv4, IPv6 or use dual stack. + + is_vip: If reserved fixed IP is a VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + ip_address: str, + network_id: str, + type: Literal["ip_address"], + is_vip: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new reserved fixed IP with the specified configuration. + + Args: + ip_address: Reserved fixed IP will be allocated the given IP address + + network_id: Reserved fixed IP will be allocated in a subnet of this network + + type: Must be 'ip_address'. + + is_vip: If reserved fixed IP is a VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + port_id: str, + type: Literal["port"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new reserved fixed IP with the specified configuration. + + Args: + port_id: Port ID to make a reserved fixed IP (for example, `vip_port_id` of the Load + Balancer entity). + + type: Must be 'port'. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args( + ["type"], + ["subnet_id", "type"], + ["network_id", "type"], + ["ip_address", "network_id", "type"], + ["port_id", "type"], + ) + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + type: Literal["external"] | Literal["subnet"] | Literal["any_subnet"] | Literal["ip_address"] | Literal["port"], + ip_family: Optional[InterfaceIPFamily] | Omit = omit, + is_vip: bool | Omit = omit, + subnet_id: str | Omit = omit, + network_id: str | Omit = omit, + ip_address: str | Omit = omit, + port_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "type": type, + "ip_family": ip_family, + "is_vip": is_vip, + "subnet_id": subnet_id, + "network_id": network_id, + "ip_address": ip_address, + "port_id": port_id, + }, + reserved_fixed_ip_create_params.ReservedFixedIPCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + is_vip: bool, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ReservedFixedIP: + """ + Update the VIP status of a reserved fixed IP. + + Args: + is_vip: If reserved fixed IP should be a VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return await self._patch( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}", + body=await async_maybe_transform( + {"is_vip": is_vip}, reserved_fixed_ip_update_params.ReservedFixedIPUpdateParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ReservedFixedIP, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + available_only: bool | Omit = omit, + device_id: str | Omit = omit, + external_only: bool | Omit = omit, + internal_only: bool | Omit = omit, + ip_address: str | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: str | Omit = omit, + vip_only: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[ReservedFixedIP, AsyncOffsetPage[ReservedFixedIP]]: + """ + List all reserved fixed IPs in the specified project and region. + + Args: + available_only: Set to true if the response should only list IP addresses that are not attached + to any instance + + device_id: Filter IPs by device ID it is attached to + + external_only: Set to true if the response should only list public IP addresses + + internal_only: Set to true if the response should only list private IP addresses + + ip_address: An IPv4 address to filter results by. Regular expression allowed + + limit: Limit the number of returned IPs + + offset: Offset value is used to exclude the first set of records from the result + + order_by: Ordering reserved fixed IP list result by name, status, `updated_at`, + `created_at` or `fixed_ip_address` fields and directions (status.asc), default + is "fixed_ip_address.asc" + + vip_only: Set to true if the response should only list VIPs + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}", + page=AsyncOffsetPage[ReservedFixedIP], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "available_only": available_only, + "device_id": device_id, + "external_only": external_only, + "internal_only": internal_only, + "ip_address": ip_address, + "limit": limit, + "offset": offset, + "order_by": order_by, + "vip_only": vip_only, + }, + reserved_fixed_ip_list_params.ReservedFixedIPListParams, + ), + ), + model=ReservedFixedIP, + ) + + async def delete( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a specific reserved fixed IP and all its associated resources. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return await self._delete( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ReservedFixedIP: + """ + Get detailed information about a specific reserved fixed IP. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return await self._get( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ReservedFixedIP, + ) + + +class ReservedFixedIPsResourceWithRawResponse: + def __init__(self, reserved_fixed_ips: ReservedFixedIPsResource) -> None: + self._reserved_fixed_ips = reserved_fixed_ips + + self.create = to_raw_response_wrapper( + reserved_fixed_ips.create, + ) + self.update = to_raw_response_wrapper( + reserved_fixed_ips.update, + ) + self.list = to_raw_response_wrapper( + reserved_fixed_ips.list, + ) + self.delete = to_raw_response_wrapper( + reserved_fixed_ips.delete, + ) + self.get = to_raw_response_wrapper( + reserved_fixed_ips.get, + ) + + @cached_property + def vip(self) -> VipResourceWithRawResponse: + return VipResourceWithRawResponse(self._reserved_fixed_ips.vip) + + +class AsyncReservedFixedIPsResourceWithRawResponse: + def __init__(self, reserved_fixed_ips: AsyncReservedFixedIPsResource) -> None: + self._reserved_fixed_ips = reserved_fixed_ips + + self.create = async_to_raw_response_wrapper( + reserved_fixed_ips.create, + ) + self.update = async_to_raw_response_wrapper( + reserved_fixed_ips.update, + ) + self.list = async_to_raw_response_wrapper( + reserved_fixed_ips.list, + ) + self.delete = async_to_raw_response_wrapper( + reserved_fixed_ips.delete, + ) + self.get = async_to_raw_response_wrapper( + reserved_fixed_ips.get, + ) + + @cached_property + def vip(self) -> AsyncVipResourceWithRawResponse: + return AsyncVipResourceWithRawResponse(self._reserved_fixed_ips.vip) + + +class ReservedFixedIPsResourceWithStreamingResponse: + def __init__(self, reserved_fixed_ips: ReservedFixedIPsResource) -> None: + self._reserved_fixed_ips = reserved_fixed_ips + + self.create = to_streamed_response_wrapper( + reserved_fixed_ips.create, + ) + self.update = to_streamed_response_wrapper( + reserved_fixed_ips.update, + ) + self.list = to_streamed_response_wrapper( + reserved_fixed_ips.list, + ) + self.delete = to_streamed_response_wrapper( + reserved_fixed_ips.delete, + ) + self.get = to_streamed_response_wrapper( + reserved_fixed_ips.get, + ) + + @cached_property + def vip(self) -> VipResourceWithStreamingResponse: + return VipResourceWithStreamingResponse(self._reserved_fixed_ips.vip) + + +class AsyncReservedFixedIPsResourceWithStreamingResponse: + def __init__(self, reserved_fixed_ips: AsyncReservedFixedIPsResource) -> None: + self._reserved_fixed_ips = reserved_fixed_ips + + self.create = async_to_streamed_response_wrapper( + reserved_fixed_ips.create, + ) + self.update = async_to_streamed_response_wrapper( + reserved_fixed_ips.update, + ) + self.list = async_to_streamed_response_wrapper( + reserved_fixed_ips.list, + ) + self.delete = async_to_streamed_response_wrapper( + reserved_fixed_ips.delete, + ) + self.get = async_to_streamed_response_wrapper( + reserved_fixed_ips.get, + ) + + @cached_property + def vip(self) -> AsyncVipResourceWithStreamingResponse: + return AsyncVipResourceWithStreamingResponse(self._reserved_fixed_ips.vip) diff --git a/src/gcore/resources/cloud/reserved_fixed_ips/vip/__init__.py b/src/gcore/resources/cloud/reserved_fixed_ips/vip/__init__.py new file mode 100644 index 00000000..81fcb02c --- /dev/null +++ b/src/gcore/resources/cloud/reserved_fixed_ips/vip/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .vip import ( + VipResource, + AsyncVipResource, + VipResourceWithRawResponse, + AsyncVipResourceWithRawResponse, + VipResourceWithStreamingResponse, + AsyncVipResourceWithStreamingResponse, +) +from .candidate_ports import ( + CandidatePortsResource, + AsyncCandidatePortsResource, + CandidatePortsResourceWithRawResponse, + AsyncCandidatePortsResourceWithRawResponse, + CandidatePortsResourceWithStreamingResponse, + AsyncCandidatePortsResourceWithStreamingResponse, +) +from .connected_ports import ( + ConnectedPortsResource, + AsyncConnectedPortsResource, + ConnectedPortsResourceWithRawResponse, + AsyncConnectedPortsResourceWithRawResponse, + ConnectedPortsResourceWithStreamingResponse, + AsyncConnectedPortsResourceWithStreamingResponse, +) + +__all__ = [ + "CandidatePortsResource", + "AsyncCandidatePortsResource", + "CandidatePortsResourceWithRawResponse", + "AsyncCandidatePortsResourceWithRawResponse", + "CandidatePortsResourceWithStreamingResponse", + "AsyncCandidatePortsResourceWithStreamingResponse", + "ConnectedPortsResource", + "AsyncConnectedPortsResource", + "ConnectedPortsResourceWithRawResponse", + "AsyncConnectedPortsResourceWithRawResponse", + "ConnectedPortsResourceWithStreamingResponse", + "AsyncConnectedPortsResourceWithStreamingResponse", + "VipResource", + "AsyncVipResource", + "VipResourceWithRawResponse", + "AsyncVipResourceWithRawResponse", + "VipResourceWithStreamingResponse", + "AsyncVipResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/reserved_fixed_ips/vip/candidate_ports.py b/src/gcore/resources/cloud/reserved_fixed_ips/vip/candidate_ports.py new file mode 100644 index 00000000..fdc29228 --- /dev/null +++ b/src/gcore/resources/cloud/reserved_fixed_ips/vip/candidate_ports.py @@ -0,0 +1,175 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import Body, Query, Headers, NotGiven, not_given +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.reserved_fixed_ips.vip.candidate_port_list import CandidatePortList + +__all__ = ["CandidatePortsResource", "AsyncCandidatePortsResource"] + + +class CandidatePortsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CandidatePortsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return CandidatePortsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CandidatePortsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return CandidatePortsResourceWithStreamingResponse(self) + + def list( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CandidatePortList: + """ + List all instance ports that are available for connecting to a VIP. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return self._get( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}/available_devices", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CandidatePortList, + ) + + +class AsyncCandidatePortsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCandidatePortsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncCandidatePortsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCandidatePortsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncCandidatePortsResourceWithStreamingResponse(self) + + async def list( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CandidatePortList: + """ + List all instance ports that are available for connecting to a VIP. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return await self._get( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}/available_devices", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CandidatePortList, + ) + + +class CandidatePortsResourceWithRawResponse: + def __init__(self, candidate_ports: CandidatePortsResource) -> None: + self._candidate_ports = candidate_ports + + self.list = to_raw_response_wrapper( + candidate_ports.list, + ) + + +class AsyncCandidatePortsResourceWithRawResponse: + def __init__(self, candidate_ports: AsyncCandidatePortsResource) -> None: + self._candidate_ports = candidate_ports + + self.list = async_to_raw_response_wrapper( + candidate_ports.list, + ) + + +class CandidatePortsResourceWithStreamingResponse: + def __init__(self, candidate_ports: CandidatePortsResource) -> None: + self._candidate_ports = candidate_ports + + self.list = to_streamed_response_wrapper( + candidate_ports.list, + ) + + +class AsyncCandidatePortsResourceWithStreamingResponse: + def __init__(self, candidate_ports: AsyncCandidatePortsResource) -> None: + self._candidate_ports = candidate_ports + + self.list = async_to_streamed_response_wrapper( + candidate_ports.list, + ) diff --git a/src/gcore/resources/cloud/reserved_fixed_ips/vip/connected_ports.py b/src/gcore/resources/cloud/reserved_fixed_ips/vip/connected_ports.py new file mode 100644 index 00000000..f98e4b8a --- /dev/null +++ b/src/gcore/resources/cloud/reserved_fixed_ips/vip/connected_ports.py @@ -0,0 +1,375 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.cloud.reserved_fixed_ips.vip import connected_port_add_params, connected_port_replace_params +from .....types.cloud.reserved_fixed_ips.vip.connected_port_list import ConnectedPortList + +__all__ = ["ConnectedPortsResource", "AsyncConnectedPortsResource"] + + +class ConnectedPortsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ConnectedPortsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ConnectedPortsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ConnectedPortsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ConnectedPortsResourceWithStreamingResponse(self) + + def list( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ConnectedPortList: + """ + List all instance ports that share a VIP. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return self._get( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}/connected_devices", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConnectedPortList, + ) + + def add( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + port_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ConnectedPortList: + """ + Add instance ports to share a VIP. + + Args: + port_ids: List of port IDs that will share one VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return self._patch( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}/connected_devices", + body=maybe_transform({"port_ids": port_ids}, connected_port_add_params.ConnectedPortAddParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConnectedPortList, + ) + + def replace( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + port_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ConnectedPortList: + """ + Replace the list of instance ports that share a VIP. + + Args: + port_ids: List of port IDs that will share one VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return self._put( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}/connected_devices", + body=maybe_transform({"port_ids": port_ids}, connected_port_replace_params.ConnectedPortReplaceParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConnectedPortList, + ) + + +class AsyncConnectedPortsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncConnectedPortsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncConnectedPortsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncConnectedPortsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncConnectedPortsResourceWithStreamingResponse(self) + + async def list( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ConnectedPortList: + """ + List all instance ports that share a VIP. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return await self._get( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}/connected_devices", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConnectedPortList, + ) + + async def add( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + port_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ConnectedPortList: + """ + Add instance ports to share a VIP. + + Args: + port_ids: List of port IDs that will share one VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return await self._patch( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}/connected_devices", + body=await async_maybe_transform({"port_ids": port_ids}, connected_port_add_params.ConnectedPortAddParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConnectedPortList, + ) + + async def replace( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + port_ids: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ConnectedPortList: + """ + Replace the list of instance ports that share a VIP. + + Args: + port_ids: List of port IDs that will share one VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return await self._put( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}/connected_devices", + body=await async_maybe_transform( + {"port_ids": port_ids}, connected_port_replace_params.ConnectedPortReplaceParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConnectedPortList, + ) + + +class ConnectedPortsResourceWithRawResponse: + def __init__(self, connected_ports: ConnectedPortsResource) -> None: + self._connected_ports = connected_ports + + self.list = to_raw_response_wrapper( + connected_ports.list, + ) + self.add = to_raw_response_wrapper( + connected_ports.add, + ) + self.replace = to_raw_response_wrapper( + connected_ports.replace, + ) + + +class AsyncConnectedPortsResourceWithRawResponse: + def __init__(self, connected_ports: AsyncConnectedPortsResource) -> None: + self._connected_ports = connected_ports + + self.list = async_to_raw_response_wrapper( + connected_ports.list, + ) + self.add = async_to_raw_response_wrapper( + connected_ports.add, + ) + self.replace = async_to_raw_response_wrapper( + connected_ports.replace, + ) + + +class ConnectedPortsResourceWithStreamingResponse: + def __init__(self, connected_ports: ConnectedPortsResource) -> None: + self._connected_ports = connected_ports + + self.list = to_streamed_response_wrapper( + connected_ports.list, + ) + self.add = to_streamed_response_wrapper( + connected_ports.add, + ) + self.replace = to_streamed_response_wrapper( + connected_ports.replace, + ) + + +class AsyncConnectedPortsResourceWithStreamingResponse: + def __init__(self, connected_ports: AsyncConnectedPortsResource) -> None: + self._connected_ports = connected_ports + + self.list = async_to_streamed_response_wrapper( + connected_ports.list, + ) + self.add = async_to_streamed_response_wrapper( + connected_ports.add, + ) + self.replace = async_to_streamed_response_wrapper( + connected_ports.replace, + ) diff --git a/src/gcore/resources/cloud/reserved_fixed_ips/vip/vip.py b/src/gcore/resources/cloud/reserved_fixed_ips/vip/vip.py new file mode 100644 index 00000000..58ff9bd5 --- /dev/null +++ b/src/gcore/resources/cloud/reserved_fixed_ips/vip/vip.py @@ -0,0 +1,249 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import Body, Query, Headers, NotGiven, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .candidate_ports import ( + CandidatePortsResource, + AsyncCandidatePortsResource, + CandidatePortsResourceWithRawResponse, + AsyncCandidatePortsResourceWithRawResponse, + CandidatePortsResourceWithStreamingResponse, + AsyncCandidatePortsResourceWithStreamingResponse, +) +from .connected_ports import ( + ConnectedPortsResource, + AsyncConnectedPortsResource, + ConnectedPortsResourceWithRawResponse, + AsyncConnectedPortsResourceWithRawResponse, + ConnectedPortsResourceWithStreamingResponse, + AsyncConnectedPortsResourceWithStreamingResponse, +) +from ....._base_client import make_request_options +from .....types.cloud.reserved_fixed_ip import ReservedFixedIP +from .....types.cloud.reserved_fixed_ips import vip_toggle_params + +__all__ = ["VipResource", "AsyncVipResource"] + + +class VipResource(SyncAPIResource): + @cached_property + def candidate_ports(self) -> CandidatePortsResource: + return CandidatePortsResource(self._client) + + @cached_property + def connected_ports(self) -> ConnectedPortsResource: + return ConnectedPortsResource(self._client) + + @cached_property + def with_raw_response(self) -> VipResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return VipResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> VipResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return VipResourceWithStreamingResponse(self) + + def toggle( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + is_vip: bool, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ReservedFixedIP: + """ + Update the VIP status of a reserved fixed IP. + + Args: + is_vip: If reserved fixed IP should be a VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return self._patch( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}", + body=maybe_transform({"is_vip": is_vip}, vip_toggle_params.VipToggleParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ReservedFixedIP, + ) + + +class AsyncVipResource(AsyncAPIResource): + @cached_property + def candidate_ports(self) -> AsyncCandidatePortsResource: + return AsyncCandidatePortsResource(self._client) + + @cached_property + def connected_ports(self) -> AsyncConnectedPortsResource: + return AsyncConnectedPortsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncVipResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncVipResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncVipResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncVipResourceWithStreamingResponse(self) + + async def toggle( + self, + port_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + is_vip: bool, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ReservedFixedIP: + """ + Update the VIP status of a reserved fixed IP. + + Args: + is_vip: If reserved fixed IP should be a VIP + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not port_id: + raise ValueError(f"Expected a non-empty value for `port_id` but received {port_id!r}") + return await self._patch( + f"/cloud/v1/reserved_fixed_ips/{project_id}/{region_id}/{port_id}", + body=await async_maybe_transform({"is_vip": is_vip}, vip_toggle_params.VipToggleParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ReservedFixedIP, + ) + + +class VipResourceWithRawResponse: + def __init__(self, vip: VipResource) -> None: + self._vip = vip + + self.toggle = to_raw_response_wrapper( + vip.toggle, + ) + + @cached_property + def candidate_ports(self) -> CandidatePortsResourceWithRawResponse: + return CandidatePortsResourceWithRawResponse(self._vip.candidate_ports) + + @cached_property + def connected_ports(self) -> ConnectedPortsResourceWithRawResponse: + return ConnectedPortsResourceWithRawResponse(self._vip.connected_ports) + + +class AsyncVipResourceWithRawResponse: + def __init__(self, vip: AsyncVipResource) -> None: + self._vip = vip + + self.toggle = async_to_raw_response_wrapper( + vip.toggle, + ) + + @cached_property + def candidate_ports(self) -> AsyncCandidatePortsResourceWithRawResponse: + return AsyncCandidatePortsResourceWithRawResponse(self._vip.candidate_ports) + + @cached_property + def connected_ports(self) -> AsyncConnectedPortsResourceWithRawResponse: + return AsyncConnectedPortsResourceWithRawResponse(self._vip.connected_ports) + + +class VipResourceWithStreamingResponse: + def __init__(self, vip: VipResource) -> None: + self._vip = vip + + self.toggle = to_streamed_response_wrapper( + vip.toggle, + ) + + @cached_property + def candidate_ports(self) -> CandidatePortsResourceWithStreamingResponse: + return CandidatePortsResourceWithStreamingResponse(self._vip.candidate_ports) + + @cached_property + def connected_ports(self) -> ConnectedPortsResourceWithStreamingResponse: + return ConnectedPortsResourceWithStreamingResponse(self._vip.connected_ports) + + +class AsyncVipResourceWithStreamingResponse: + def __init__(self, vip: AsyncVipResource) -> None: + self._vip = vip + + self.toggle = async_to_streamed_response_wrapper( + vip.toggle, + ) + + @cached_property + def candidate_ports(self) -> AsyncCandidatePortsResourceWithStreamingResponse: + return AsyncCandidatePortsResourceWithStreamingResponse(self._vip.candidate_ports) + + @cached_property + def connected_ports(self) -> AsyncConnectedPortsResourceWithStreamingResponse: + return AsyncConnectedPortsResourceWithStreamingResponse(self._vip.connected_ports) diff --git a/src/gcore/resources/cloud/secrets.py b/src/gcore/resources/cloud/secrets.py new file mode 100644 index 00000000..e23a92ad --- /dev/null +++ b/src/gcore/resources/cloud/secrets.py @@ -0,0 +1,550 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ...types.cloud import secret_list_params, secret_upload_tls_certificate_params +from ..._base_client import AsyncPaginator, make_request_options +from ...types.cloud.secret import Secret +from ...types.cloud.task_id_list import TaskIDList + +__all__ = ["SecretsResource", "AsyncSecretsResource"] + + +class SecretsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SecretsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return SecretsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SecretsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return SecretsResourceWithStreamingResponse(self) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[Secret]: + """ + List secrets + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/secrets/{project_id}/{region_id}", + page=SyncOffsetPage[Secret], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + secret_list_params.SecretListParams, + ), + ), + model=Secret, + ) + + def delete( + self, + secret_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete secret + + Args: + project_id: Project ID + + region_id: Region ID + + secret_id: Secret ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not secret_id: + raise ValueError(f"Expected a non-empty value for `secret_id` but received {secret_id!r}") + return self._delete( + f"/cloud/v1/secrets/{project_id}/{region_id}/{secret_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + secret_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Secret: + """ + Get secret + + Args: + project_id: Project ID + + region_id: Region ID + + secret_id: Secret ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not secret_id: + raise ValueError(f"Expected a non-empty value for `secret_id` but received {secret_id!r}") + return self._get( + f"/cloud/v1/secrets/{project_id}/{region_id}/{secret_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Secret, + ) + + def upload_tls_certificate( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + payload: secret_upload_tls_certificate_params.Payload, + expiration: Union[str, datetime, None] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create secret + + Args: + project_id: Project ID + + region_id: Region ID + + name: Secret name + + payload: Secret payload. + + expiration: Datetime when the secret will expire. Defaults to None + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v2/secrets/{project_id}/{region_id}", + body=maybe_transform( + { + "name": name, + "payload": payload, + "expiration": expiration, + }, + secret_upload_tls_certificate_params.SecretUploadTlsCertificateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class AsyncSecretsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSecretsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncSecretsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSecretsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncSecretsResourceWithStreamingResponse(self) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Secret, AsyncOffsetPage[Secret]]: + """ + List secrets + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Optional. Limit the number of returned items + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/secrets/{project_id}/{region_id}", + page=AsyncOffsetPage[Secret], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + secret_list_params.SecretListParams, + ), + ), + model=Secret, + ) + + async def delete( + self, + secret_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete secret + + Args: + project_id: Project ID + + region_id: Region ID + + secret_id: Secret ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not secret_id: + raise ValueError(f"Expected a non-empty value for `secret_id` but received {secret_id!r}") + return await self._delete( + f"/cloud/v1/secrets/{project_id}/{region_id}/{secret_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + secret_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Secret: + """ + Get secret + + Args: + project_id: Project ID + + region_id: Region ID + + secret_id: Secret ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not secret_id: + raise ValueError(f"Expected a non-empty value for `secret_id` but received {secret_id!r}") + return await self._get( + f"/cloud/v1/secrets/{project_id}/{region_id}/{secret_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Secret, + ) + + async def upload_tls_certificate( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + payload: secret_upload_tls_certificate_params.Payload, + expiration: Union[str, datetime, None] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create secret + + Args: + project_id: Project ID + + region_id: Region ID + + name: Secret name + + payload: Secret payload. + + expiration: Datetime when the secret will expire. Defaults to None + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v2/secrets/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "name": name, + "payload": payload, + "expiration": expiration, + }, + secret_upload_tls_certificate_params.SecretUploadTlsCertificateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class SecretsResourceWithRawResponse: + def __init__(self, secrets: SecretsResource) -> None: + self._secrets = secrets + + self.list = to_raw_response_wrapper( + secrets.list, + ) + self.delete = to_raw_response_wrapper( + secrets.delete, + ) + self.get = to_raw_response_wrapper( + secrets.get, + ) + self.upload_tls_certificate = to_raw_response_wrapper( + secrets.upload_tls_certificate, + ) + + +class AsyncSecretsResourceWithRawResponse: + def __init__(self, secrets: AsyncSecretsResource) -> None: + self._secrets = secrets + + self.list = async_to_raw_response_wrapper( + secrets.list, + ) + self.delete = async_to_raw_response_wrapper( + secrets.delete, + ) + self.get = async_to_raw_response_wrapper( + secrets.get, + ) + self.upload_tls_certificate = async_to_raw_response_wrapper( + secrets.upload_tls_certificate, + ) + + +class SecretsResourceWithStreamingResponse: + def __init__(self, secrets: SecretsResource) -> None: + self._secrets = secrets + + self.list = to_streamed_response_wrapper( + secrets.list, + ) + self.delete = to_streamed_response_wrapper( + secrets.delete, + ) + self.get = to_streamed_response_wrapper( + secrets.get, + ) + self.upload_tls_certificate = to_streamed_response_wrapper( + secrets.upload_tls_certificate, + ) + + +class AsyncSecretsResourceWithStreamingResponse: + def __init__(self, secrets: AsyncSecretsResource) -> None: + self._secrets = secrets + + self.list = async_to_streamed_response_wrapper( + secrets.list, + ) + self.delete = async_to_streamed_response_wrapper( + secrets.delete, + ) + self.get = async_to_streamed_response_wrapper( + secrets.get, + ) + self.upload_tls_certificate = async_to_streamed_response_wrapper( + secrets.upload_tls_certificate, + ) diff --git a/src/gcore/resources/cloud/security_groups/__init__.py b/src/gcore/resources/cloud/security_groups/__init__.py new file mode 100644 index 00000000..8671970e --- /dev/null +++ b/src/gcore/resources/cloud/security_groups/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .rules import ( + RulesResource, + AsyncRulesResource, + RulesResourceWithRawResponse, + AsyncRulesResourceWithRawResponse, + RulesResourceWithStreamingResponse, + AsyncRulesResourceWithStreamingResponse, +) +from .security_groups import ( + SecurityGroupsResource, + AsyncSecurityGroupsResource, + SecurityGroupsResourceWithRawResponse, + AsyncSecurityGroupsResourceWithRawResponse, + SecurityGroupsResourceWithStreamingResponse, + AsyncSecurityGroupsResourceWithStreamingResponse, +) + +__all__ = [ + "RulesResource", + "AsyncRulesResource", + "RulesResourceWithRawResponse", + "AsyncRulesResourceWithRawResponse", + "RulesResourceWithStreamingResponse", + "AsyncRulesResourceWithStreamingResponse", + "SecurityGroupsResource", + "AsyncSecurityGroupsResource", + "SecurityGroupsResourceWithRawResponse", + "AsyncSecurityGroupsResourceWithRawResponse", + "SecurityGroupsResourceWithStreamingResponse", + "AsyncSecurityGroupsResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/security_groups/rules.py b/src/gcore/resources/cloud/security_groups/rules.py new file mode 100644 index 00000000..31a01883 --- /dev/null +++ b/src/gcore/resources/cloud/security_groups/rules.py @@ -0,0 +1,717 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import typing_extensions +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.cloud.security_groups import rule_create_params, rule_replace_params +from ....types.cloud.security_group_rule import SecurityGroupRule + +__all__ = ["RulesResource", "AsyncRulesResource"] + + +class RulesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return RulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return RulesResourceWithStreamingResponse(self) + + @typing_extensions.deprecated("deprecated") + def create( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + direction: Literal["egress", "ingress"], + description: str | Omit = omit, + ethertype: Literal["IPv4", "IPv6"] | Omit = omit, + port_range_max: Optional[int] | Omit = omit, + port_range_min: Optional[int] | Omit = omit, + protocol: Literal[ + "ah", + "any", + "dccp", + "egp", + "esp", + "gre", + "icmp", + "igmp", + "ipencap", + "ipip", + "ipv6-encap", + "ipv6-frag", + "ipv6-icmp", + "ipv6-nonxt", + "ipv6-opts", + "ipv6-route", + "ospf", + "pgm", + "rsvp", + "sctp", + "tcp", + "udp", + "udplite", + "vrrp", + ] + | Omit = omit, + remote_group_id: str | Omit = omit, + remote_ip_prefix: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecurityGroupRule: + """ + Add a new rule to an existing security group. + + **Deprecated** Use + `/v2/security_groups////rules` instead. + + Args: + project_id: Project ID + + region_id: Region ID + + group_id: Group ID + + direction: Ingress or egress, which is the direction in which the security group is applied + + description: Rule description + + ethertype: Ether type + + port_range_max: The maximum port number in the range that is matched by the security group rule + + port_range_min: The minimum port number in the range that is matched by the security group rule + + protocol: Protocol + + remote_group_id: The remote group UUID to associate with this security group + + remote_ip_prefix: The remote IP prefix that is matched by this security group rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._post( + f"/cloud/v1/securitygroups/{project_id}/{region_id}/{group_id}/rules", + body=maybe_transform( + { + "direction": direction, + "description": description, + "ethertype": ethertype, + "port_range_max": port_range_max, + "port_range_min": port_range_min, + "protocol": protocol, + "remote_group_id": remote_group_id, + "remote_ip_prefix": remote_ip_prefix, + }, + rule_create_params.RuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecurityGroupRule, + ) + + @typing_extensions.deprecated("deprecated") + def delete( + self, + rule_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific rule from a security group. + + **Deprecated** Use + `/v2/security_groups////rules/` + instead. + + Args: + project_id: Project ID + + region_id: Region ID + + rule_id: Rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not rule_id: + raise ValueError(f"Expected a non-empty value for `rule_id` but received {rule_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v1/securitygrouprules/{project_id}/{region_id}/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + @typing_extensions.deprecated("deprecated") + def replace( + self, + rule_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + direction: Literal["egress", "ingress"], + security_group_id: str, + description: str | Omit = omit, + ethertype: Optional[Literal["IPv4", "IPv6"]] | Omit = omit, + port_range_max: Optional[int] | Omit = omit, + port_range_min: Optional[int] | Omit = omit, + protocol: Literal[ + "ah", + "any", + "dccp", + "egp", + "esp", + "gre", + "icmp", + "igmp", + "ipencap", + "ipip", + "ipv6-encap", + "ipv6-frag", + "ipv6-icmp", + "ipv6-nonxt", + "ipv6-opts", + "ipv6-route", + "ospf", + "pgm", + "rsvp", + "sctp", + "tcp", + "udp", + "udplite", + "vrrp", + ] + | Omit = omit, + remote_group_id: Optional[str] | Omit = omit, + remote_ip_prefix: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecurityGroupRule: + """ + Update the configuration of an existing security group rule. + + **Deprecated** Use + `/v2/security_groups////rules/` to + delete and `/v2/security_groups////rules` to + create a new rule. + + Args: + project_id: Project ID + + region_id: Region ID + + rule_id: Rule ID + + direction: Ingress or egress, which is the direction in which the security group rule is + applied + + security_group_id: Parent security group of this rule + + description: Rule description + + ethertype: Must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress + or egress rules. + + port_range_max: The maximum port number in the range that is matched by the security group rule + + port_range_min: The minimum port number in the range that is matched by the security group rule + + protocol: Protocol + + remote_group_id: The remote group UUID to associate with this security group rule + + remote_ip_prefix: The remote IP prefix that is matched by this security group rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not rule_id: + raise ValueError(f"Expected a non-empty value for `rule_id` but received {rule_id!r}") + return self._put( + f"/cloud/v1/securitygrouprules/{project_id}/{region_id}/{rule_id}", + body=maybe_transform( + { + "direction": direction, + "security_group_id": security_group_id, + "description": description, + "ethertype": ethertype, + "port_range_max": port_range_max, + "port_range_min": port_range_min, + "protocol": protocol, + "remote_group_id": remote_group_id, + "remote_ip_prefix": remote_ip_prefix, + }, + rule_replace_params.RuleReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecurityGroupRule, + ) + + +class AsyncRulesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncRulesResourceWithStreamingResponse(self) + + @typing_extensions.deprecated("deprecated") + async def create( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + direction: Literal["egress", "ingress"], + description: str | Omit = omit, + ethertype: Literal["IPv4", "IPv6"] | Omit = omit, + port_range_max: Optional[int] | Omit = omit, + port_range_min: Optional[int] | Omit = omit, + protocol: Literal[ + "ah", + "any", + "dccp", + "egp", + "esp", + "gre", + "icmp", + "igmp", + "ipencap", + "ipip", + "ipv6-encap", + "ipv6-frag", + "ipv6-icmp", + "ipv6-nonxt", + "ipv6-opts", + "ipv6-route", + "ospf", + "pgm", + "rsvp", + "sctp", + "tcp", + "udp", + "udplite", + "vrrp", + ] + | Omit = omit, + remote_group_id: str | Omit = omit, + remote_ip_prefix: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecurityGroupRule: + """ + Add a new rule to an existing security group. + + **Deprecated** Use + `/v2/security_groups////rules` instead. + + Args: + project_id: Project ID + + region_id: Region ID + + group_id: Group ID + + direction: Ingress or egress, which is the direction in which the security group is applied + + description: Rule description + + ethertype: Ether type + + port_range_max: The maximum port number in the range that is matched by the security group rule + + port_range_min: The minimum port number in the range that is matched by the security group rule + + protocol: Protocol + + remote_group_id: The remote group UUID to associate with this security group + + remote_ip_prefix: The remote IP prefix that is matched by this security group rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._post( + f"/cloud/v1/securitygroups/{project_id}/{region_id}/{group_id}/rules", + body=await async_maybe_transform( + { + "direction": direction, + "description": description, + "ethertype": ethertype, + "port_range_max": port_range_max, + "port_range_min": port_range_min, + "protocol": protocol, + "remote_group_id": remote_group_id, + "remote_ip_prefix": remote_ip_prefix, + }, + rule_create_params.RuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecurityGroupRule, + ) + + @typing_extensions.deprecated("deprecated") + async def delete( + self, + rule_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific rule from a security group. + + **Deprecated** Use + `/v2/security_groups////rules/` + instead. + + Args: + project_id: Project ID + + region_id: Region ID + + rule_id: Rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not rule_id: + raise ValueError(f"Expected a non-empty value for `rule_id` but received {rule_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v1/securitygrouprules/{project_id}/{region_id}/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + @typing_extensions.deprecated("deprecated") + async def replace( + self, + rule_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + direction: Literal["egress", "ingress"], + security_group_id: str, + description: str | Omit = omit, + ethertype: Optional[Literal["IPv4", "IPv6"]] | Omit = omit, + port_range_max: Optional[int] | Omit = omit, + port_range_min: Optional[int] | Omit = omit, + protocol: Literal[ + "ah", + "any", + "dccp", + "egp", + "esp", + "gre", + "icmp", + "igmp", + "ipencap", + "ipip", + "ipv6-encap", + "ipv6-frag", + "ipv6-icmp", + "ipv6-nonxt", + "ipv6-opts", + "ipv6-route", + "ospf", + "pgm", + "rsvp", + "sctp", + "tcp", + "udp", + "udplite", + "vrrp", + ] + | Omit = omit, + remote_group_id: Optional[str] | Omit = omit, + remote_ip_prefix: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecurityGroupRule: + """ + Update the configuration of an existing security group rule. + + **Deprecated** Use + `/v2/security_groups////rules/` to + delete and `/v2/security_groups////rules` to + create a new rule. + + Args: + project_id: Project ID + + region_id: Region ID + + rule_id: Rule ID + + direction: Ingress or egress, which is the direction in which the security group rule is + applied + + security_group_id: Parent security group of this rule + + description: Rule description + + ethertype: Must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress + or egress rules. + + port_range_max: The maximum port number in the range that is matched by the security group rule + + port_range_min: The minimum port number in the range that is matched by the security group rule + + protocol: Protocol + + remote_group_id: The remote group UUID to associate with this security group rule + + remote_ip_prefix: The remote IP prefix that is matched by this security group rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not rule_id: + raise ValueError(f"Expected a non-empty value for `rule_id` but received {rule_id!r}") + return await self._put( + f"/cloud/v1/securitygrouprules/{project_id}/{region_id}/{rule_id}", + body=await async_maybe_transform( + { + "direction": direction, + "security_group_id": security_group_id, + "description": description, + "ethertype": ethertype, + "port_range_max": port_range_max, + "port_range_min": port_range_min, + "protocol": protocol, + "remote_group_id": remote_group_id, + "remote_ip_prefix": remote_ip_prefix, + }, + rule_replace_params.RuleReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecurityGroupRule, + ) + + +class RulesResourceWithRawResponse: + def __init__(self, rules: RulesResource) -> None: + self._rules = rules + + self.create = ( # pyright: ignore[reportDeprecated] + to_raw_response_wrapper( + rules.create, # pyright: ignore[reportDeprecated], + ) + ) + self.delete = ( # pyright: ignore[reportDeprecated] + to_raw_response_wrapper( + rules.delete, # pyright: ignore[reportDeprecated], + ) + ) + self.replace = ( # pyright: ignore[reportDeprecated] + to_raw_response_wrapper( + rules.replace, # pyright: ignore[reportDeprecated], + ) + ) + + +class AsyncRulesResourceWithRawResponse: + def __init__(self, rules: AsyncRulesResource) -> None: + self._rules = rules + + self.create = ( # pyright: ignore[reportDeprecated] + async_to_raw_response_wrapper( + rules.create, # pyright: ignore[reportDeprecated], + ) + ) + self.delete = ( # pyright: ignore[reportDeprecated] + async_to_raw_response_wrapper( + rules.delete, # pyright: ignore[reportDeprecated], + ) + ) + self.replace = ( # pyright: ignore[reportDeprecated] + async_to_raw_response_wrapper( + rules.replace, # pyright: ignore[reportDeprecated], + ) + ) + + +class RulesResourceWithStreamingResponse: + def __init__(self, rules: RulesResource) -> None: + self._rules = rules + + self.create = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + rules.create, # pyright: ignore[reportDeprecated], + ) + ) + self.delete = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + rules.delete, # pyright: ignore[reportDeprecated], + ) + ) + self.replace = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + rules.replace, # pyright: ignore[reportDeprecated], + ) + ) + + +class AsyncRulesResourceWithStreamingResponse: + def __init__(self, rules: AsyncRulesResource) -> None: + self._rules = rules + + self.create = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + rules.create, # pyright: ignore[reportDeprecated], + ) + ) + self.delete = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + rules.delete, # pyright: ignore[reportDeprecated], + ) + ) + self.replace = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + rules.replace, # pyright: ignore[reportDeprecated], + ) + ) diff --git a/src/gcore/resources/cloud/security_groups/security_groups.py b/src/gcore/resources/cloud/security_groups/security_groups.py new file mode 100644 index 00000000..909cd448 --- /dev/null +++ b/src/gcore/resources/cloud/security_groups/security_groups.py @@ -0,0 +1,1067 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional + +import httpx + +from .rules import ( + RulesResource, + AsyncRulesResource, + RulesResourceWithRawResponse, + AsyncRulesResourceWithRawResponse, + RulesResourceWithStreamingResponse, + AsyncRulesResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ....types.cloud import ( + security_group_copy_params, + security_group_list_params, + security_group_create_params, + security_group_update_params, +) +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.task_id_list import TaskIDList +from ....types.cloud.security_group import SecurityGroup +from ....types.cloud.tag_update_map_param import TagUpdateMapParam + +__all__ = ["SecurityGroupsResource", "AsyncSecurityGroupsResource"] + + +class SecurityGroupsResource(SyncAPIResource): + @cached_property + def rules(self) -> RulesResource: + return RulesResource(self._client) + + @cached_property + def with_raw_response(self) -> SecurityGroupsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return SecurityGroupsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SecurityGroupsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return SecurityGroupsResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + description: str | Omit = omit, + rules: Iterable[security_group_create_params.Rule] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Creates a new security group with the specified configuration. + + If no egress + rules are provided, default set of egress rules will be applied If rules are + explicitly set to empty, no rules will be created. + + Args: + project_id: Project ID + + region_id: Region ID + + name: Security group name + + description: Security group description + + rules: Security group rules + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v2/security_groups/{project_id}/{region_id}", + body=maybe_transform( + { + "name": name, + "description": description, + "rules": rules, + "tags": tags, + }, + security_group_create_params.SecurityGroupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + description: str | Omit = omit, + name: str | Omit = omit, + rules: Iterable[security_group_update_params.Rule] | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Updates the specified security group with the provided changes. + + **Behavior:** + + - Simple fields (name, description) will be updated if provided + - Undefined fields will remain unchanged + - If no change is detected for a specific field compared to the current security + group state, that field will be skipped + - If no changes are detected at all across all fields, no task will be created + and an empty task list will be returned + + **Important - Security Group Rules:** + + - Rules must be specified completely as the desired final state + - The system compares the provided rules against the current state + - Rules that exist in the request but not in the current state will be added + - Rules that exist in the current state but not in the request will be removed + - To keep existing rules, they must be included in the request alongside any new + rules + + Args: + project_id: Project ID + + region_id: Region ID + + group_id: Security group ID + + description: Security group description + + name: Name + + rules: Security group rules + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._patch( + f"/cloud/v2/security_groups/{project_id}/{region_id}/{group_id}", + body=maybe_transform( + { + "description": description, + "name": name, + "rules": rules, + "tags": tags, + }, + security_group_update_params.SecurityGroupUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[SecurityGroup]: + """ + List all security groups in the specified project and region. + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Limit of items on a single page + + name: Optional. Filter by name. Must be specified a full name of the security group. + + offset: Offset in results list + + tag_key: Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2 + + tag_key_value: Optional. Filter by tag key-value pairs. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/securitygroups/{project_id}/{region_id}", + page=SyncOffsetPage[SecurityGroup], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "name": name, + "offset": offset, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + }, + security_group_list_params.SecurityGroupListParams, + ), + ), + model=SecurityGroup, + ) + + def delete( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific security group and all its associated rules. + + Args: + project_id: Project ID + + region_id: Region ID + + group_id: Group ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v1/securitygroups/{project_id}/{region_id}/{group_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def copy( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecurityGroup: + """ + Create a deep copy of an existing security group. + + Args: + project_id: Project ID + + region_id: Region ID + + group_id: Group ID + + name: Name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._post( + f"/cloud/v1/securitygroups/{project_id}/{region_id}/{group_id}/copy", + body=maybe_transform({"name": name}, security_group_copy_params.SecurityGroupCopyParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecurityGroup, + ) + + def get( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecurityGroup: + """ + Get detailed information about a specific security group. + + Args: + project_id: Project ID + + region_id: Region ID + + group_id: Group ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._get( + f"/cloud/v1/securitygroups/{project_id}/{region_id}/{group_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecurityGroup, + ) + + def revert_to_default( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecurityGroup: + """ + Revert a security group to its previous state. + + Args: + project_id: Project ID + + region_id: Region ID + + group_id: Group ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._post( + f"/cloud/v1/securitygroups/{project_id}/{region_id}/{group_id}/revert", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecurityGroup, + ) + + +class AsyncSecurityGroupsResource(AsyncAPIResource): + @cached_property + def rules(self) -> AsyncRulesResource: + return AsyncRulesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncSecurityGroupsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncSecurityGroupsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSecurityGroupsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncSecurityGroupsResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + description: str | Omit = omit, + rules: Iterable[security_group_create_params.Rule] | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Creates a new security group with the specified configuration. + + If no egress + rules are provided, default set of egress rules will be applied If rules are + explicitly set to empty, no rules will be created. + + Args: + project_id: Project ID + + region_id: Region ID + + name: Security group name + + description: Security group description + + rules: Security group rules + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v2/security_groups/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "name": name, + "description": description, + "rules": rules, + "tags": tags, + }, + security_group_create_params.SecurityGroupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + description: str | Omit = omit, + name: str | Omit = omit, + rules: Iterable[security_group_update_params.Rule] | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Updates the specified security group with the provided changes. + + **Behavior:** + + - Simple fields (name, description) will be updated if provided + - Undefined fields will remain unchanged + - If no change is detected for a specific field compared to the current security + group state, that field will be skipped + - If no changes are detected at all across all fields, no task will be created + and an empty task list will be returned + + **Important - Security Group Rules:** + + - Rules must be specified completely as the desired final state + - The system compares the provided rules against the current state + - Rules that exist in the request but not in the current state will be added + - Rules that exist in the current state but not in the request will be removed + - To keep existing rules, they must be included in the request alongside any new + rules + + Args: + project_id: Project ID + + region_id: Region ID + + group_id: Security group ID + + description: Security group description + + name: Name + + rules: Security group rules + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._patch( + f"/cloud/v2/security_groups/{project_id}/{region_id}/{group_id}", + body=await async_maybe_transform( + { + "description": description, + "name": name, + "rules": rules, + "tags": tags, + }, + security_group_update_params.SecurityGroupUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[SecurityGroup, AsyncOffsetPage[SecurityGroup]]: + """ + List all security groups in the specified project and region. + + Args: + project_id: Project ID + + region_id: Region ID + + limit: Limit of items on a single page + + name: Optional. Filter by name. Must be specified a full name of the security group. + + offset: Offset in results list + + tag_key: Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2 + + tag_key_value: Optional. Filter by tag key-value pairs. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/securitygroups/{project_id}/{region_id}", + page=AsyncOffsetPage[SecurityGroup], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "name": name, + "offset": offset, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + }, + security_group_list_params.SecurityGroupListParams, + ), + ), + model=SecurityGroup, + ) + + async def delete( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific security group and all its associated rules. + + Args: + project_id: Project ID + + region_id: Region ID + + group_id: Group ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v1/securitygroups/{project_id}/{region_id}/{group_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def copy( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecurityGroup: + """ + Create a deep copy of an existing security group. + + Args: + project_id: Project ID + + region_id: Region ID + + group_id: Group ID + + name: Name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._post( + f"/cloud/v1/securitygroups/{project_id}/{region_id}/{group_id}/copy", + body=await async_maybe_transform({"name": name}, security_group_copy_params.SecurityGroupCopyParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecurityGroup, + ) + + async def get( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecurityGroup: + """ + Get detailed information about a specific security group. + + Args: + project_id: Project ID + + region_id: Region ID + + group_id: Group ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._get( + f"/cloud/v1/securitygroups/{project_id}/{region_id}/{group_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecurityGroup, + ) + + async def revert_to_default( + self, + group_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecurityGroup: + """ + Revert a security group to its previous state. + + Args: + project_id: Project ID + + region_id: Region ID + + group_id: Group ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._post( + f"/cloud/v1/securitygroups/{project_id}/{region_id}/{group_id}/revert", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecurityGroup, + ) + + +class SecurityGroupsResourceWithRawResponse: + def __init__(self, security_groups: SecurityGroupsResource) -> None: + self._security_groups = security_groups + + self.create = to_raw_response_wrapper( + security_groups.create, + ) + self.update = to_raw_response_wrapper( + security_groups.update, + ) + self.list = to_raw_response_wrapper( + security_groups.list, + ) + self.delete = to_raw_response_wrapper( + security_groups.delete, + ) + self.copy = to_raw_response_wrapper( + security_groups.copy, + ) + self.get = to_raw_response_wrapper( + security_groups.get, + ) + self.revert_to_default = to_raw_response_wrapper( + security_groups.revert_to_default, + ) + + @cached_property + def rules(self) -> RulesResourceWithRawResponse: + return RulesResourceWithRawResponse(self._security_groups.rules) + + +class AsyncSecurityGroupsResourceWithRawResponse: + def __init__(self, security_groups: AsyncSecurityGroupsResource) -> None: + self._security_groups = security_groups + + self.create = async_to_raw_response_wrapper( + security_groups.create, + ) + self.update = async_to_raw_response_wrapper( + security_groups.update, + ) + self.list = async_to_raw_response_wrapper( + security_groups.list, + ) + self.delete = async_to_raw_response_wrapper( + security_groups.delete, + ) + self.copy = async_to_raw_response_wrapper( + security_groups.copy, + ) + self.get = async_to_raw_response_wrapper( + security_groups.get, + ) + self.revert_to_default = async_to_raw_response_wrapper( + security_groups.revert_to_default, + ) + + @cached_property + def rules(self) -> AsyncRulesResourceWithRawResponse: + return AsyncRulesResourceWithRawResponse(self._security_groups.rules) + + +class SecurityGroupsResourceWithStreamingResponse: + def __init__(self, security_groups: SecurityGroupsResource) -> None: + self._security_groups = security_groups + + self.create = to_streamed_response_wrapper( + security_groups.create, + ) + self.update = to_streamed_response_wrapper( + security_groups.update, + ) + self.list = to_streamed_response_wrapper( + security_groups.list, + ) + self.delete = to_streamed_response_wrapper( + security_groups.delete, + ) + self.copy = to_streamed_response_wrapper( + security_groups.copy, + ) + self.get = to_streamed_response_wrapper( + security_groups.get, + ) + self.revert_to_default = to_streamed_response_wrapper( + security_groups.revert_to_default, + ) + + @cached_property + def rules(self) -> RulesResourceWithStreamingResponse: + return RulesResourceWithStreamingResponse(self._security_groups.rules) + + +class AsyncSecurityGroupsResourceWithStreamingResponse: + def __init__(self, security_groups: AsyncSecurityGroupsResource) -> None: + self._security_groups = security_groups + + self.create = async_to_streamed_response_wrapper( + security_groups.create, + ) + self.update = async_to_streamed_response_wrapper( + security_groups.update, + ) + self.list = async_to_streamed_response_wrapper( + security_groups.list, + ) + self.delete = async_to_streamed_response_wrapper( + security_groups.delete, + ) + self.copy = async_to_streamed_response_wrapper( + security_groups.copy, + ) + self.get = async_to_streamed_response_wrapper( + security_groups.get, + ) + self.revert_to_default = async_to_streamed_response_wrapper( + security_groups.revert_to_default, + ) + + @cached_property + def rules(self) -> AsyncRulesResourceWithStreamingResponse: + return AsyncRulesResourceWithStreamingResponse(self._security_groups.rules) diff --git a/src/gcore/resources/cloud/ssh_keys.py b/src/gcore/resources/cloud/ssh_keys.py new file mode 100644 index 00000000..cd2c058d --- /dev/null +++ b/src/gcore/resources/cloud/ssh_keys.py @@ -0,0 +1,645 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ...types.cloud import ssh_key_list_params, ssh_key_create_params, ssh_key_update_params +from ..._base_client import AsyncPaginator, make_request_options +from ...types.cloud.ssh_key import SSHKey +from ...types.cloud.ssh_key_created import SSHKeyCreated + +__all__ = ["SSHKeysResource", "AsyncSSHKeysResource"] + + +class SSHKeysResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SSHKeysResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return SSHKeysResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SSHKeysResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return SSHKeysResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + name: str, + public_key: str | Omit = omit, + shared_in_project: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SSHKeyCreated: + """ + To generate a key, omit the `public_key` parameter from the request body + + Args: + project_id: Project ID + + name: SSH key name + + public_key: The public part of an SSH key is the shareable portion of an SSH key pair. It + can be safely sent to servers or services to grant access. It does not contain + sensitive information. + + - If you’re uploading your own key, provide the public part here (usually found + in a file like `id_ed25519.pub`). + - If you want the platform to generate an Ed25519 key pair for you, leave this + field empty — the system will return the private key in the response **once + only**. + + shared_in_project: SSH key is shared with all users in the project + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._post( + f"/cloud/v1/ssh_keys/{project_id}", + body=maybe_transform( + { + "name": name, + "public_key": public_key, + "shared_in_project": shared_in_project, + }, + ssh_key_create_params.SSHKeyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SSHKeyCreated, + ) + + def update( + self, + ssh_key_id: str, + *, + project_id: int | None = None, + shared_in_project: bool, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SSHKey: + """ + Share or unshare SSH key with users + + Args: + project_id: Project ID + + ssh_key_id: SSH key ID + + shared_in_project: Share your ssh key with all users in the project + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not ssh_key_id: + raise ValueError(f"Expected a non-empty value for `ssh_key_id` but received {ssh_key_id!r}") + return self._patch( + f"/cloud/v1/ssh_keys/{project_id}/{ssh_key_id}", + body=maybe_transform({"shared_in_project": shared_in_project}, ssh_key_update_params.SSHKeyUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SSHKey, + ) + + def list( + self, + *, + project_id: int | None = None, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["created_at.asc", "created_at.desc", "name.asc", "name.desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[SSHKey]: + """ + List SSH keys + + Args: + project_id: Project ID + + limit: Maximum number of SSH keys to return + + name: SSH key name. Partial substring match. Example: `name=abc` matches any key + containing `abc` in name. + + offset: Offset for pagination + + order_by: Sort order for the SSH keys + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._get_api_list( + f"/cloud/v1/ssh_keys/{project_id}", + page=SyncOffsetPage[SSHKey], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "name": name, + "offset": offset, + "order_by": order_by, + }, + ssh_key_list_params.SSHKeyListParams, + ), + ), + model=SSHKey, + ) + + def delete( + self, + ssh_key_id: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete SSH key + + Args: + project_id: Project ID + + ssh_key_id: SSH key ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not ssh_key_id: + raise ValueError(f"Expected a non-empty value for `ssh_key_id` but received {ssh_key_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/cloud/v1/ssh_keys/{project_id}/{ssh_key_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + ssh_key_id: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SSHKey: + """ + Get SSH key + + Args: + project_id: Project ID + + ssh_key_id: SSH key ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not ssh_key_id: + raise ValueError(f"Expected a non-empty value for `ssh_key_id` but received {ssh_key_id!r}") + return self._get( + f"/cloud/v1/ssh_keys/{project_id}/{ssh_key_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SSHKey, + ) + + +class AsyncSSHKeysResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSSHKeysResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncSSHKeysResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSSHKeysResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncSSHKeysResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + name: str, + public_key: str | Omit = omit, + shared_in_project: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SSHKeyCreated: + """ + To generate a key, omit the `public_key` parameter from the request body + + Args: + project_id: Project ID + + name: SSH key name + + public_key: The public part of an SSH key is the shareable portion of an SSH key pair. It + can be safely sent to servers or services to grant access. It does not contain + sensitive information. + + - If you’re uploading your own key, provide the public part here (usually found + in a file like `id_ed25519.pub`). + - If you want the platform to generate an Ed25519 key pair for you, leave this + field empty — the system will return the private key in the response **once + only**. + + shared_in_project: SSH key is shared with all users in the project + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return await self._post( + f"/cloud/v1/ssh_keys/{project_id}", + body=await async_maybe_transform( + { + "name": name, + "public_key": public_key, + "shared_in_project": shared_in_project, + }, + ssh_key_create_params.SSHKeyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SSHKeyCreated, + ) + + async def update( + self, + ssh_key_id: str, + *, + project_id: int | None = None, + shared_in_project: bool, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SSHKey: + """ + Share or unshare SSH key with users + + Args: + project_id: Project ID + + ssh_key_id: SSH key ID + + shared_in_project: Share your ssh key with all users in the project + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not ssh_key_id: + raise ValueError(f"Expected a non-empty value for `ssh_key_id` but received {ssh_key_id!r}") + return await self._patch( + f"/cloud/v1/ssh_keys/{project_id}/{ssh_key_id}", + body=await async_maybe_transform( + {"shared_in_project": shared_in_project}, ssh_key_update_params.SSHKeyUpdateParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SSHKey, + ) + + def list( + self, + *, + project_id: int | None = None, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["created_at.asc", "created_at.desc", "name.asc", "name.desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[SSHKey, AsyncOffsetPage[SSHKey]]: + """ + List SSH keys + + Args: + project_id: Project ID + + limit: Maximum number of SSH keys to return + + name: SSH key name. Partial substring match. Example: `name=abc` matches any key + containing `abc` in name. + + offset: Offset for pagination + + order_by: Sort order for the SSH keys + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + return self._get_api_list( + f"/cloud/v1/ssh_keys/{project_id}", + page=AsyncOffsetPage[SSHKey], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "name": name, + "offset": offset, + "order_by": order_by, + }, + ssh_key_list_params.SSHKeyListParams, + ), + ), + model=SSHKey, + ) + + async def delete( + self, + ssh_key_id: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete SSH key + + Args: + project_id: Project ID + + ssh_key_id: SSH key ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not ssh_key_id: + raise ValueError(f"Expected a non-empty value for `ssh_key_id` but received {ssh_key_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/cloud/v1/ssh_keys/{project_id}/{ssh_key_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + ssh_key_id: str, + *, + project_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SSHKey: + """ + Get SSH key + + Args: + project_id: Project ID + + ssh_key_id: SSH key ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if not ssh_key_id: + raise ValueError(f"Expected a non-empty value for `ssh_key_id` but received {ssh_key_id!r}") + return await self._get( + f"/cloud/v1/ssh_keys/{project_id}/{ssh_key_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SSHKey, + ) + + +class SSHKeysResourceWithRawResponse: + def __init__(self, ssh_keys: SSHKeysResource) -> None: + self._ssh_keys = ssh_keys + + self.create = to_raw_response_wrapper( + ssh_keys.create, + ) + self.update = to_raw_response_wrapper( + ssh_keys.update, + ) + self.list = to_raw_response_wrapper( + ssh_keys.list, + ) + self.delete = to_raw_response_wrapper( + ssh_keys.delete, + ) + self.get = to_raw_response_wrapper( + ssh_keys.get, + ) + + +class AsyncSSHKeysResourceWithRawResponse: + def __init__(self, ssh_keys: AsyncSSHKeysResource) -> None: + self._ssh_keys = ssh_keys + + self.create = async_to_raw_response_wrapper( + ssh_keys.create, + ) + self.update = async_to_raw_response_wrapper( + ssh_keys.update, + ) + self.list = async_to_raw_response_wrapper( + ssh_keys.list, + ) + self.delete = async_to_raw_response_wrapper( + ssh_keys.delete, + ) + self.get = async_to_raw_response_wrapper( + ssh_keys.get, + ) + + +class SSHKeysResourceWithStreamingResponse: + def __init__(self, ssh_keys: SSHKeysResource) -> None: + self._ssh_keys = ssh_keys + + self.create = to_streamed_response_wrapper( + ssh_keys.create, + ) + self.update = to_streamed_response_wrapper( + ssh_keys.update, + ) + self.list = to_streamed_response_wrapper( + ssh_keys.list, + ) + self.delete = to_streamed_response_wrapper( + ssh_keys.delete, + ) + self.get = to_streamed_response_wrapper( + ssh_keys.get, + ) + + +class AsyncSSHKeysResourceWithStreamingResponse: + def __init__(self, ssh_keys: AsyncSSHKeysResource) -> None: + self._ssh_keys = ssh_keys + + self.create = async_to_streamed_response_wrapper( + ssh_keys.create, + ) + self.update = async_to_streamed_response_wrapper( + ssh_keys.update, + ) + self.list = async_to_streamed_response_wrapper( + ssh_keys.list, + ) + self.delete = async_to_streamed_response_wrapper( + ssh_keys.delete, + ) + self.get = async_to_streamed_response_wrapper( + ssh_keys.get, + ) diff --git a/src/gcore/resources/cloud/tasks.py b/src/gcore/resources/cloud/tasks.py new file mode 100644 index 00000000..298ff821 --- /dev/null +++ b/src/gcore/resources/cloud/tasks.py @@ -0,0 +1,646 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ...types.cloud import task_list_params, task_acknowledge_all_params +from ..._base_client import AsyncPaginator, make_request_options +from ...types.cloud.task import Task + +__all__ = ["TasksResource", "AsyncTasksResource"] + + +class TasksResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> TasksResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return TasksResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TasksResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return TasksResourceWithStreamingResponse(self) + + def list( + self, + *, + from_timestamp: Union[str, datetime] | Omit = omit, + is_acknowledged: bool | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["asc", "desc"] | Omit = omit, + project_id: Iterable[int] | Omit = omit, + region_id: Iterable[int] | Omit = omit, + sorting: Literal["asc", "desc"] | Omit = omit, + state: List[Literal["ERROR", "FINISHED", "NEW", "RUNNING"]] | Omit = omit, + task_type: str | Omit = omit, + to_timestamp: Union[str, datetime] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[Task]: + """List tasks + + Args: + from_timestamp: ISO formatted datetime string. + + Filter the tasks by creation date greater than or + equal to `from_timestamp` + + is_acknowledged: Filter the tasks by their acknowledgement status + + limit: Limit the number of returned tasks. Falls back to default of 10 if not + specified. Limited by max limit value of 1000 + + offset: Offset value is used to exclude the first set of records from the result + + order_by: Sorting by creation date. Oldest first, or most recent first + + project_id: The project ID to filter the tasks by project. Supports multiple values of kind + key=value1&key=value2 + + region_id: The region ID to filter the tasks by region. Supports multiple values of kind + key=value1&key=value2 + + sorting: (DEPRECATED Use 'order_by' instead) Sorting by creation date. Oldest first, or + most recent first + + state: Filter the tasks by state. Supports multiple values of kind + key=value1&key=value2 + + task_type: Filter the tasks by their type one of ['activate_ddos_profile', + 'attach_bm_to_reserved_fixed_ip', 'attach_vm_interface', + 'attach_vm_to_reserved_fixed_ip', 'attach_volume', 'create_ai_cluster_gpu', + 'create_bm', 'create_caas_container', 'create_dbaas_postgres_cluster', + 'create_ddos_profile', 'create_faas_function', 'create_faas_namespace', + 'create_fip', 'create_gpu_virtual_cluster', 'create_image', + 'create_inference_application', 'create_inference_instance', + 'create_k8s_cluster_pool_v2', 'create_k8s_cluster_v2', 'create_l7policy', + 'create_l7rule', 'create_lblistener', 'create_lbmember', 'create_lbpool', + 'create_lbpool_health_monitor', 'create_loadbalancer', 'create_network', + 'create_reserved_fixed_ip', 'create_router', 'create_secret', + 'create_security_group', 'create_security_group_rule', 'create_servergroup', + 'create_sfs', 'create_snapshot', 'create_subnet', 'create_vm', 'create_volume', + 'deactivate_ddos_profile', 'delete_ai_cluster_gpu', 'delete_caas_container', + 'delete_dbaas_postgres_cluster', 'delete_ddos_profile', 'delete_faas_function', + 'delete_faas_namespace', 'delete_fip', 'delete_gpu_virtual_cluster', + 'delete_gpu_virtual_server', 'delete_image', 'delete_inference_application', + 'delete_inference_instance', 'delete_k8s_cluster_pool_v2', + 'delete_k8s_cluster_v2', 'delete_l7policy', 'delete_l7rule', + 'delete_lblistener', 'delete_lbmember', 'delete_lbmetadata', 'delete_lbpool', + 'delete_loadbalancer', 'delete_network', 'delete_project', + 'delete_reserved_fixed_ip', 'delete_router', 'delete_secret', + 'delete_security_group_rule', 'delete_servergroup', 'delete_sfs', + 'delete_snapshot', 'delete_subnet', 'delete_vm', 'delete_volume', + 'detach_vm_interface', 'detach_volume', 'download_image', + 'downscale_ai_cluster_gpu', 'downscale_gpu_virtual_cluster', 'extend_sfs', + 'extend_volume', 'failover_loadbalancer', 'hard_reboot_gpu_baremetal_server', + 'hard_reboot_gpu_virtual_cluster', 'hard_reboot_gpu_virtual_server', + 'hard_reboot_vm', 'patch_caas_container', 'patch_dbaas_postgres_cluster', + 'patch_faas_function', 'patch_faas_namespace', 'patch_lblistener', + 'patch_lbpool', 'put_into_server_group', 'put_l7rule', 'rebuild_bm', + 'rebuild_gpu_baremetal_cluster', 'rebuild_gpu_baremetal_node', + 'rebuild_gpu_baremetal_server', 'remove_from_server_group', + 'replace_lbmetadata', 'resize_k8s_cluster_v2', 'resize_loadbalancer', + 'resize_vm', 'resume_vm', 'revert_volume', 'soft_reboot_gpu_baremetal_server', + 'soft_reboot_gpu_virtual_cluster', 'soft_reboot_gpu_virtual_server', + 'soft_reboot_vm', 'start_gpu_baremetal_server', 'start_gpu_virtual_cluster', + 'start_gpu_virtual_server', 'start_vm', 'stop_gpu_baremetal_server', + 'stop_gpu_virtual_cluster', 'stop_gpu_virtual_server', 'stop_vm', 'suspend_vm', + 'sync_private_flavors', 'update_ddos_profile', 'update_floating_ip', + 'update_inference_application', 'update_inference_instance', + 'update_k8s_cluster_v2', 'update_l7policy', 'update_lbmetadata', + 'update_loadbalancer', 'update_port_allowed_address_pairs', 'update_router', + 'update_security_group', 'update_sfs', 'update_tags_gpu_virtual_cluster', + 'upgrade_k8s_cluster_v2', 'upscale_ai_cluster_gpu', + 'upscale_gpu_virtual_cluster'] + + to_timestamp: ISO formatted datetime string. Filter the tasks by creation date less than or + equal to `to_timestamp` + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v1/tasks", + page=SyncOffsetPage[Task], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_timestamp": from_timestamp, + "is_acknowledged": is_acknowledged, + "limit": limit, + "offset": offset, + "order_by": order_by, + "project_id": project_id, + "region_id": region_id, + "sorting": sorting, + "state": state, + "task_type": task_type, + "to_timestamp": to_timestamp, + }, + task_list_params.TaskListParams, + ), + ), + model=Task, + ) + + def acknowledge_all( + self, + *, + project_id: int | Omit = omit, + region_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Acknowledge all tasks + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + "/cloud/v1/tasks/acknowledge_all", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "project_id": project_id, + "region_id": region_id, + }, + task_acknowledge_all_params.TaskAcknowledgeAllParams, + ), + ), + cast_to=NoneType, + ) + + def acknowledge_one( + self, + task_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Task: + """ + Acknowledge one task + + Args: + task_id: Task ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not task_id: + raise ValueError(f"Expected a non-empty value for `task_id` but received {task_id!r}") + return self._post( + f"/cloud/v1/tasks/{task_id}/acknowledge", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Task, + ) + + def get( + self, + task_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Task: + """ + Get task + + Args: + task_id: Task ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not task_id: + raise ValueError(f"Expected a non-empty value for `task_id` but received {task_id!r}") + return self._get( + f"/cloud/v1/tasks/{task_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Task, + ) + + +class AsyncTasksResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncTasksResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncTasksResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTasksResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncTasksResourceWithStreamingResponse(self) + + def list( + self, + *, + from_timestamp: Union[str, datetime] | Omit = omit, + is_acknowledged: bool | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: Literal["asc", "desc"] | Omit = omit, + project_id: Iterable[int] | Omit = omit, + region_id: Iterable[int] | Omit = omit, + sorting: Literal["asc", "desc"] | Omit = omit, + state: List[Literal["ERROR", "FINISHED", "NEW", "RUNNING"]] | Omit = omit, + task_type: str | Omit = omit, + to_timestamp: Union[str, datetime] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Task, AsyncOffsetPage[Task]]: + """List tasks + + Args: + from_timestamp: ISO formatted datetime string. + + Filter the tasks by creation date greater than or + equal to `from_timestamp` + + is_acknowledged: Filter the tasks by their acknowledgement status + + limit: Limit the number of returned tasks. Falls back to default of 10 if not + specified. Limited by max limit value of 1000 + + offset: Offset value is used to exclude the first set of records from the result + + order_by: Sorting by creation date. Oldest first, or most recent first + + project_id: The project ID to filter the tasks by project. Supports multiple values of kind + key=value1&key=value2 + + region_id: The region ID to filter the tasks by region. Supports multiple values of kind + key=value1&key=value2 + + sorting: (DEPRECATED Use 'order_by' instead) Sorting by creation date. Oldest first, or + most recent first + + state: Filter the tasks by state. Supports multiple values of kind + key=value1&key=value2 + + task_type: Filter the tasks by their type one of ['activate_ddos_profile', + 'attach_bm_to_reserved_fixed_ip', 'attach_vm_interface', + 'attach_vm_to_reserved_fixed_ip', 'attach_volume', 'create_ai_cluster_gpu', + 'create_bm', 'create_caas_container', 'create_dbaas_postgres_cluster', + 'create_ddos_profile', 'create_faas_function', 'create_faas_namespace', + 'create_fip', 'create_gpu_virtual_cluster', 'create_image', + 'create_inference_application', 'create_inference_instance', + 'create_k8s_cluster_pool_v2', 'create_k8s_cluster_v2', 'create_l7policy', + 'create_l7rule', 'create_lblistener', 'create_lbmember', 'create_lbpool', + 'create_lbpool_health_monitor', 'create_loadbalancer', 'create_network', + 'create_reserved_fixed_ip', 'create_router', 'create_secret', + 'create_security_group', 'create_security_group_rule', 'create_servergroup', + 'create_sfs', 'create_snapshot', 'create_subnet', 'create_vm', 'create_volume', + 'deactivate_ddos_profile', 'delete_ai_cluster_gpu', 'delete_caas_container', + 'delete_dbaas_postgres_cluster', 'delete_ddos_profile', 'delete_faas_function', + 'delete_faas_namespace', 'delete_fip', 'delete_gpu_virtual_cluster', + 'delete_gpu_virtual_server', 'delete_image', 'delete_inference_application', + 'delete_inference_instance', 'delete_k8s_cluster_pool_v2', + 'delete_k8s_cluster_v2', 'delete_l7policy', 'delete_l7rule', + 'delete_lblistener', 'delete_lbmember', 'delete_lbmetadata', 'delete_lbpool', + 'delete_loadbalancer', 'delete_network', 'delete_project', + 'delete_reserved_fixed_ip', 'delete_router', 'delete_secret', + 'delete_security_group_rule', 'delete_servergroup', 'delete_sfs', + 'delete_snapshot', 'delete_subnet', 'delete_vm', 'delete_volume', + 'detach_vm_interface', 'detach_volume', 'download_image', + 'downscale_ai_cluster_gpu', 'downscale_gpu_virtual_cluster', 'extend_sfs', + 'extend_volume', 'failover_loadbalancer', 'hard_reboot_gpu_baremetal_server', + 'hard_reboot_gpu_virtual_cluster', 'hard_reboot_gpu_virtual_server', + 'hard_reboot_vm', 'patch_caas_container', 'patch_dbaas_postgres_cluster', + 'patch_faas_function', 'patch_faas_namespace', 'patch_lblistener', + 'patch_lbpool', 'put_into_server_group', 'put_l7rule', 'rebuild_bm', + 'rebuild_gpu_baremetal_cluster', 'rebuild_gpu_baremetal_node', + 'rebuild_gpu_baremetal_server', 'remove_from_server_group', + 'replace_lbmetadata', 'resize_k8s_cluster_v2', 'resize_loadbalancer', + 'resize_vm', 'resume_vm', 'revert_volume', 'soft_reboot_gpu_baremetal_server', + 'soft_reboot_gpu_virtual_cluster', 'soft_reboot_gpu_virtual_server', + 'soft_reboot_vm', 'start_gpu_baremetal_server', 'start_gpu_virtual_cluster', + 'start_gpu_virtual_server', 'start_vm', 'stop_gpu_baremetal_server', + 'stop_gpu_virtual_cluster', 'stop_gpu_virtual_server', 'stop_vm', 'suspend_vm', + 'sync_private_flavors', 'update_ddos_profile', 'update_floating_ip', + 'update_inference_application', 'update_inference_instance', + 'update_k8s_cluster_v2', 'update_l7policy', 'update_lbmetadata', + 'update_loadbalancer', 'update_port_allowed_address_pairs', 'update_router', + 'update_security_group', 'update_sfs', 'update_tags_gpu_virtual_cluster', + 'upgrade_k8s_cluster_v2', 'upscale_ai_cluster_gpu', + 'upscale_gpu_virtual_cluster'] + + to_timestamp: ISO formatted datetime string. Filter the tasks by creation date less than or + equal to `to_timestamp` + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v1/tasks", + page=AsyncOffsetPage[Task], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_timestamp": from_timestamp, + "is_acknowledged": is_acknowledged, + "limit": limit, + "offset": offset, + "order_by": order_by, + "project_id": project_id, + "region_id": region_id, + "sorting": sorting, + "state": state, + "task_type": task_type, + "to_timestamp": to_timestamp, + }, + task_list_params.TaskListParams, + ), + ), + model=Task, + ) + + async def acknowledge_all( + self, + *, + project_id: int | Omit = omit, + region_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Acknowledge all tasks + + Args: + project_id: Project ID + + region_id: Region ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + "/cloud/v1/tasks/acknowledge_all", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "project_id": project_id, + "region_id": region_id, + }, + task_acknowledge_all_params.TaskAcknowledgeAllParams, + ), + ), + cast_to=NoneType, + ) + + async def acknowledge_one( + self, + task_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Task: + """ + Acknowledge one task + + Args: + task_id: Task ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not task_id: + raise ValueError(f"Expected a non-empty value for `task_id` but received {task_id!r}") + return await self._post( + f"/cloud/v1/tasks/{task_id}/acknowledge", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Task, + ) + + async def get( + self, + task_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Task: + """ + Get task + + Args: + task_id: Task ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not task_id: + raise ValueError(f"Expected a non-empty value for `task_id` but received {task_id!r}") + return await self._get( + f"/cloud/v1/tasks/{task_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Task, + ) + + +class TasksResourceWithRawResponse: + def __init__(self, tasks: TasksResource) -> None: + self._tasks = tasks + + self.list = to_raw_response_wrapper( + tasks.list, + ) + self.acknowledge_all = to_raw_response_wrapper( + tasks.acknowledge_all, + ) + self.acknowledge_one = to_raw_response_wrapper( + tasks.acknowledge_one, + ) + self.get = to_raw_response_wrapper( + tasks.get, + ) + + +class AsyncTasksResourceWithRawResponse: + def __init__(self, tasks: AsyncTasksResource) -> None: + self._tasks = tasks + + self.list = async_to_raw_response_wrapper( + tasks.list, + ) + self.acknowledge_all = async_to_raw_response_wrapper( + tasks.acknowledge_all, + ) + self.acknowledge_one = async_to_raw_response_wrapper( + tasks.acknowledge_one, + ) + self.get = async_to_raw_response_wrapper( + tasks.get, + ) + + +class TasksResourceWithStreamingResponse: + def __init__(self, tasks: TasksResource) -> None: + self._tasks = tasks + + self.list = to_streamed_response_wrapper( + tasks.list, + ) + self.acknowledge_all = to_streamed_response_wrapper( + tasks.acknowledge_all, + ) + self.acknowledge_one = to_streamed_response_wrapper( + tasks.acknowledge_one, + ) + self.get = to_streamed_response_wrapper( + tasks.get, + ) + + +class AsyncTasksResourceWithStreamingResponse: + def __init__(self, tasks: AsyncTasksResource) -> None: + self._tasks = tasks + + self.list = async_to_streamed_response_wrapper( + tasks.list, + ) + self.acknowledge_all = async_to_streamed_response_wrapper( + tasks.acknowledge_all, + ) + self.acknowledge_one = async_to_streamed_response_wrapper( + tasks.acknowledge_one, + ) + self.get = async_to_streamed_response_wrapper( + tasks.get, + ) diff --git a/src/gcore/resources/cloud/usage_reports.py b/src/gcore/resources/cloud/usage_reports.py new file mode 100644 index 00000000..0cb9178c --- /dev/null +++ b/src/gcore/resources/cloud/usage_reports.py @@ -0,0 +1,335 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable, Optional +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cloud import usage_report_get_params +from ..._base_client import make_request_options +from ...types.cloud.usage_report import UsageReport + +__all__ = ["UsageReportsResource", "AsyncUsageReportsResource"] + + +class UsageReportsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> UsageReportsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return UsageReportsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> UsageReportsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return UsageReportsResourceWithStreamingResponse(self) + + def get( + self, + *, + time_from: Union[str, datetime], + time_to: Union[str, datetime], + enable_last_day: bool | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + projects: Optional[Iterable[int]] | Omit = omit, + regions: Iterable[int] | Omit = omit, + schema_filter: usage_report_get_params.SchemaFilter | Omit = omit, + sorting: Iterable[usage_report_get_params.Sorting] | Omit = omit, + tags: usage_report_get_params.Tags | Omit = omit, + types: List[ + Literal[ + "ai_cluster", + "ai_virtual_cluster", + "backup", + "baremetal", + "basic_vm", + "containers", + "dbaas_postgresql_connection_pooler", + "dbaas_postgresql_cpu", + "dbaas_postgresql_memory", + "dbaas_postgresql_public_network", + "dbaas_postgresql_volume", + "egress_traffic", + "external_ip", + "file_share", + "floatingip", + "functions", + "functions_calls", + "functions_traffic", + "image", + "inference", + "instance", + "load_balancer", + "log_index", + "snapshot", + "volume", + ] + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageReport: + """Data from the past hour may not reflect the full set of statistics. + + For the most + complete and accurate results, we recommend accessing the data at least one hour + after the relevant time period. Updates are generally available within a 24-hour + window, though timing can vary. Scheduled maintenance or other exceptions may + occasionally cause delays beyond 24 hours. + + Args: + time_from: The start date of the report period (ISO 8601). The report starts from the + beginning of this day in UTC. + + time_to: The end date of the report period (ISO 8601). The report ends just before the + beginning of this day in UTC. + + enable_last_day: Expenses for the last specified day are taken into account. As the default, + False. + + limit: The response resources limit. Defaults to 10. + + offset: The response resources offset. + + projects: List of project IDs + + regions: List of region IDs. + + schema_filter: Extended filter for field filtering. + + sorting: List of sorting filters (JSON objects) fields: project. directions: asc, desc. + + tags: Filter by tags + + types: List of resource types to be filtered in the report. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/cloud/v1/usage_report", + body=maybe_transform( + { + "time_from": time_from, + "time_to": time_to, + "enable_last_day": enable_last_day, + "limit": limit, + "offset": offset, + "projects": projects, + "regions": regions, + "schema_filter": schema_filter, + "sorting": sorting, + "tags": tags, + "types": types, + }, + usage_report_get_params.UsageReportGetParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UsageReport, + ) + + +class AsyncUsageReportsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncUsageReportsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncUsageReportsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncUsageReportsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncUsageReportsResourceWithStreamingResponse(self) + + async def get( + self, + *, + time_from: Union[str, datetime], + time_to: Union[str, datetime], + enable_last_day: bool | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + projects: Optional[Iterable[int]] | Omit = omit, + regions: Iterable[int] | Omit = omit, + schema_filter: usage_report_get_params.SchemaFilter | Omit = omit, + sorting: Iterable[usage_report_get_params.Sorting] | Omit = omit, + tags: usage_report_get_params.Tags | Omit = omit, + types: List[ + Literal[ + "ai_cluster", + "ai_virtual_cluster", + "backup", + "baremetal", + "basic_vm", + "containers", + "dbaas_postgresql_connection_pooler", + "dbaas_postgresql_cpu", + "dbaas_postgresql_memory", + "dbaas_postgresql_public_network", + "dbaas_postgresql_volume", + "egress_traffic", + "external_ip", + "file_share", + "floatingip", + "functions", + "functions_calls", + "functions_traffic", + "image", + "inference", + "instance", + "load_balancer", + "log_index", + "snapshot", + "volume", + ] + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageReport: + """Data from the past hour may not reflect the full set of statistics. + + For the most + complete and accurate results, we recommend accessing the data at least one hour + after the relevant time period. Updates are generally available within a 24-hour + window, though timing can vary. Scheduled maintenance or other exceptions may + occasionally cause delays beyond 24 hours. + + Args: + time_from: The start date of the report period (ISO 8601). The report starts from the + beginning of this day in UTC. + + time_to: The end date of the report period (ISO 8601). The report ends just before the + beginning of this day in UTC. + + enable_last_day: Expenses for the last specified day are taken into account. As the default, + False. + + limit: The response resources limit. Defaults to 10. + + offset: The response resources offset. + + projects: List of project IDs + + regions: List of region IDs. + + schema_filter: Extended filter for field filtering. + + sorting: List of sorting filters (JSON objects) fields: project. directions: asc, desc. + + tags: Filter by tags + + types: List of resource types to be filtered in the report. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/cloud/v1/usage_report", + body=await async_maybe_transform( + { + "time_from": time_from, + "time_to": time_to, + "enable_last_day": enable_last_day, + "limit": limit, + "offset": offset, + "projects": projects, + "regions": regions, + "schema_filter": schema_filter, + "sorting": sorting, + "tags": tags, + "types": types, + }, + usage_report_get_params.UsageReportGetParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UsageReport, + ) + + +class UsageReportsResourceWithRawResponse: + def __init__(self, usage_reports: UsageReportsResource) -> None: + self._usage_reports = usage_reports + + self.get = to_raw_response_wrapper( + usage_reports.get, + ) + + +class AsyncUsageReportsResourceWithRawResponse: + def __init__(self, usage_reports: AsyncUsageReportsResource) -> None: + self._usage_reports = usage_reports + + self.get = async_to_raw_response_wrapper( + usage_reports.get, + ) + + +class UsageReportsResourceWithStreamingResponse: + def __init__(self, usage_reports: UsageReportsResource) -> None: + self._usage_reports = usage_reports + + self.get = to_streamed_response_wrapper( + usage_reports.get, + ) + + +class AsyncUsageReportsResourceWithStreamingResponse: + def __init__(self, usage_reports: AsyncUsageReportsResource) -> None: + self._usage_reports = usage_reports + + self.get = async_to_streamed_response_wrapper( + usage_reports.get, + ) diff --git a/src/gcore/resources/cloud/users/__init__.py b/src/gcore/resources/cloud/users/__init__.py new file mode 100644 index 00000000..43e07e09 --- /dev/null +++ b/src/gcore/resources/cloud/users/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .users import ( + UsersResource, + AsyncUsersResource, + UsersResourceWithRawResponse, + AsyncUsersResourceWithRawResponse, + UsersResourceWithStreamingResponse, + AsyncUsersResourceWithStreamingResponse, +) +from .role_assignments import ( + RoleAssignmentsResource, + AsyncRoleAssignmentsResource, + RoleAssignmentsResourceWithRawResponse, + AsyncRoleAssignmentsResourceWithRawResponse, + RoleAssignmentsResourceWithStreamingResponse, + AsyncRoleAssignmentsResourceWithStreamingResponse, +) + +__all__ = [ + "RoleAssignmentsResource", + "AsyncRoleAssignmentsResource", + "RoleAssignmentsResourceWithRawResponse", + "AsyncRoleAssignmentsResourceWithRawResponse", + "RoleAssignmentsResourceWithStreamingResponse", + "AsyncRoleAssignmentsResourceWithStreamingResponse", + "UsersResource", + "AsyncUsersResource", + "UsersResourceWithRawResponse", + "AsyncUsersResourceWithRawResponse", + "UsersResourceWithStreamingResponse", + "AsyncUsersResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/cloud/users/role_assignments.py b/src/gcore/resources/cloud/users/role_assignments.py new file mode 100644 index 00000000..db6f6bd4 --- /dev/null +++ b/src/gcore/resources/cloud/users/role_assignments.py @@ -0,0 +1,532 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.cloud.users import ( + role_assignment_list_params, + role_assignment_create_params, + role_assignment_update_params, +) +from ....types.cloud.users.role_assignment import RoleAssignment +from ....types.cloud.users.role_assignment_updated_deleted import RoleAssignmentUpdatedDeleted + +__all__ = ["RoleAssignmentsResource", "AsyncRoleAssignmentsResource"] + + +class RoleAssignmentsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RoleAssignmentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return RoleAssignmentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RoleAssignmentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return RoleAssignmentsResourceWithStreamingResponse(self) + + def create( + self, + *, + role: Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"], + user_id: int, + client_id: Optional[int] | Omit = omit, + project_id: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleAssignment: + """ + Assign a role to an existing user in the specified scope. + + Args: + role: User role + + user_id: User ID + + client_id: Client ID. Required if `project_id` is specified + + project_id: Project ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/cloud/v1/users/assignments", + body=maybe_transform( + { + "role": role, + "user_id": user_id, + "client_id": client_id, + "project_id": project_id, + }, + role_assignment_create_params.RoleAssignmentCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RoleAssignment, + ) + + def update( + self, + assignment_id: int, + *, + role: Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"], + user_id: int, + client_id: Optional[int] | Omit = omit, + project_id: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleAssignmentUpdatedDeleted: + """ + Modify an existing role assignment for a user. + + Args: + assignment_id: Assignment ID + + role: User role + + user_id: User ID + + client_id: Client ID. Required if `project_id` is specified + + project_id: Project ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/cloud/v1/users/assignments/{assignment_id}", + body=maybe_transform( + { + "role": role, + "user_id": user_id, + "client_id": client_id, + "project_id": project_id, + }, + role_assignment_update_params.RoleAssignmentUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RoleAssignmentUpdatedDeleted, + ) + + def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + project_id: int | Omit = omit, + user_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[RoleAssignment]: + """ + List all role assignments in the specified scope. + + Args: + limit: Limit the number of returned items. Falls back to default of 1000 if not + specified. Limited by max limit value of 1000 + + offset: Offset value is used to exclude the first set of records from the result + + project_id: Project ID + + user_id: User ID for filtering + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v1/users/assignments", + page=SyncOffsetPage[RoleAssignment], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + "project_id": project_id, + "user_id": user_id, + }, + role_assignment_list_params.RoleAssignmentListParams, + ), + ), + model=RoleAssignment, + ) + + def delete( + self, + assignment_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleAssignmentUpdatedDeleted: + """ + Delete an existing role assignment. + + Args: + assignment_id: Assignment ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._delete( + f"/cloud/v1/users/assignments/{assignment_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RoleAssignmentUpdatedDeleted, + ) + + +class AsyncRoleAssignmentsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRoleAssignmentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncRoleAssignmentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRoleAssignmentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncRoleAssignmentsResourceWithStreamingResponse(self) + + async def create( + self, + *, + role: Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"], + user_id: int, + client_id: Optional[int] | Omit = omit, + project_id: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleAssignment: + """ + Assign a role to an existing user in the specified scope. + + Args: + role: User role + + user_id: User ID + + client_id: Client ID. Required if `project_id` is specified + + project_id: Project ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/cloud/v1/users/assignments", + body=await async_maybe_transform( + { + "role": role, + "user_id": user_id, + "client_id": client_id, + "project_id": project_id, + }, + role_assignment_create_params.RoleAssignmentCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RoleAssignment, + ) + + async def update( + self, + assignment_id: int, + *, + role: Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"], + user_id: int, + client_id: Optional[int] | Omit = omit, + project_id: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleAssignmentUpdatedDeleted: + """ + Modify an existing role assignment for a user. + + Args: + assignment_id: Assignment ID + + role: User role + + user_id: User ID + + client_id: Client ID. Required if `project_id` is specified + + project_id: Project ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/cloud/v1/users/assignments/{assignment_id}", + body=await async_maybe_transform( + { + "role": role, + "user_id": user_id, + "client_id": client_id, + "project_id": project_id, + }, + role_assignment_update_params.RoleAssignmentUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RoleAssignmentUpdatedDeleted, + ) + + def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + project_id: int | Omit = omit, + user_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[RoleAssignment, AsyncOffsetPage[RoleAssignment]]: + """ + List all role assignments in the specified scope. + + Args: + limit: Limit the number of returned items. Falls back to default of 1000 if not + specified. Limited by max limit value of 1000 + + offset: Offset value is used to exclude the first set of records from the result + + project_id: Project ID + + user_id: User ID for filtering + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/cloud/v1/users/assignments", + page=AsyncOffsetPage[RoleAssignment], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + "project_id": project_id, + "user_id": user_id, + }, + role_assignment_list_params.RoleAssignmentListParams, + ), + ), + model=RoleAssignment, + ) + + async def delete( + self, + assignment_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RoleAssignmentUpdatedDeleted: + """ + Delete an existing role assignment. + + Args: + assignment_id: Assignment ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._delete( + f"/cloud/v1/users/assignments/{assignment_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RoleAssignmentUpdatedDeleted, + ) + + +class RoleAssignmentsResourceWithRawResponse: + def __init__(self, role_assignments: RoleAssignmentsResource) -> None: + self._role_assignments = role_assignments + + self.create = to_raw_response_wrapper( + role_assignments.create, + ) + self.update = to_raw_response_wrapper( + role_assignments.update, + ) + self.list = to_raw_response_wrapper( + role_assignments.list, + ) + self.delete = to_raw_response_wrapper( + role_assignments.delete, + ) + + +class AsyncRoleAssignmentsResourceWithRawResponse: + def __init__(self, role_assignments: AsyncRoleAssignmentsResource) -> None: + self._role_assignments = role_assignments + + self.create = async_to_raw_response_wrapper( + role_assignments.create, + ) + self.update = async_to_raw_response_wrapper( + role_assignments.update, + ) + self.list = async_to_raw_response_wrapper( + role_assignments.list, + ) + self.delete = async_to_raw_response_wrapper( + role_assignments.delete, + ) + + +class RoleAssignmentsResourceWithStreamingResponse: + def __init__(self, role_assignments: RoleAssignmentsResource) -> None: + self._role_assignments = role_assignments + + self.create = to_streamed_response_wrapper( + role_assignments.create, + ) + self.update = to_streamed_response_wrapper( + role_assignments.update, + ) + self.list = to_streamed_response_wrapper( + role_assignments.list, + ) + self.delete = to_streamed_response_wrapper( + role_assignments.delete, + ) + + +class AsyncRoleAssignmentsResourceWithStreamingResponse: + def __init__(self, role_assignments: AsyncRoleAssignmentsResource) -> None: + self._role_assignments = role_assignments + + self.create = async_to_streamed_response_wrapper( + role_assignments.create, + ) + self.update = async_to_streamed_response_wrapper( + role_assignments.update, + ) + self.list = async_to_streamed_response_wrapper( + role_assignments.list, + ) + self.delete = async_to_streamed_response_wrapper( + role_assignments.delete, + ) diff --git a/src/gcore/resources/cloud/users/users.py b/src/gcore/resources/cloud/users/users.py new file mode 100644 index 00000000..f70eabac --- /dev/null +++ b/src/gcore/resources/cloud/users/users.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from .role_assignments import ( + RoleAssignmentsResource, + AsyncRoleAssignmentsResource, + RoleAssignmentsResourceWithRawResponse, + AsyncRoleAssignmentsResourceWithRawResponse, + RoleAssignmentsResourceWithStreamingResponse, + AsyncRoleAssignmentsResourceWithStreamingResponse, +) + +__all__ = ["UsersResource", "AsyncUsersResource"] + + +class UsersResource(SyncAPIResource): + @cached_property + def role_assignments(self) -> RoleAssignmentsResource: + return RoleAssignmentsResource(self._client) + + @cached_property + def with_raw_response(self) -> UsersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return UsersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> UsersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return UsersResourceWithStreamingResponse(self) + + +class AsyncUsersResource(AsyncAPIResource): + @cached_property + def role_assignments(self) -> AsyncRoleAssignmentsResource: + return AsyncRoleAssignmentsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncUsersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncUsersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncUsersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncUsersResourceWithStreamingResponse(self) + + +class UsersResourceWithRawResponse: + def __init__(self, users: UsersResource) -> None: + self._users = users + + @cached_property + def role_assignments(self) -> RoleAssignmentsResourceWithRawResponse: + return RoleAssignmentsResourceWithRawResponse(self._users.role_assignments) + + +class AsyncUsersResourceWithRawResponse: + def __init__(self, users: AsyncUsersResource) -> None: + self._users = users + + @cached_property + def role_assignments(self) -> AsyncRoleAssignmentsResourceWithRawResponse: + return AsyncRoleAssignmentsResourceWithRawResponse(self._users.role_assignments) + + +class UsersResourceWithStreamingResponse: + def __init__(self, users: UsersResource) -> None: + self._users = users + + @cached_property + def role_assignments(self) -> RoleAssignmentsResourceWithStreamingResponse: + return RoleAssignmentsResourceWithStreamingResponse(self._users.role_assignments) + + +class AsyncUsersResourceWithStreamingResponse: + def __init__(self, users: AsyncUsersResource) -> None: + self._users = users + + @cached_property + def role_assignments(self) -> AsyncRoleAssignmentsResourceWithStreamingResponse: + return AsyncRoleAssignmentsResourceWithStreamingResponse(self._users.role_assignments) diff --git a/src/gcore/resources/cloud/volume_snapshots.py b/src/gcore/resources/cloud/volume_snapshots.py new file mode 100644 index 00000000..52dc4971 --- /dev/null +++ b/src/gcore/resources/cloud/volume_snapshots.py @@ -0,0 +1,601 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.cloud import volume_snapshot_create_params, volume_snapshot_update_params +from ..._base_client import make_request_options +from ...types.cloud.snapshot import Snapshot +from ...types.cloud.task_id_list import TaskIDList +from ...types.cloud.tag_update_map_param import TagUpdateMapParam + +__all__ = ["VolumeSnapshotsResource", "AsyncVolumeSnapshotsResource"] + + +class VolumeSnapshotsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> VolumeSnapshotsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return VolumeSnapshotsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> VolumeSnapshotsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return VolumeSnapshotsResourceWithStreamingResponse(self) + + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + volume_id: str, + description: str | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new snapshot from a volume. + + Args: + name: Snapshot name + + volume_id: Volume ID to make snapshot of + + description: Snapshot description + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/snapshots/{project_id}/{region_id}", + body=maybe_transform( + { + "name": name, + "volume_id": volume_id, + "description": description, + "tags": tags, + }, + volume_snapshot_create_params.VolumeSnapshotCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + snapshot_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Snapshot: + """ + Rename snapshot or update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + snapshot_id: Unique identifier of the snapshot + + name: Display name for the snapshot (3-63 chars). Used in customer portal and API. + Does not affect snapshot data. + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not snapshot_id: + raise ValueError(f"Expected a non-empty value for `snapshot_id` but received {snapshot_id!r}") + return self._patch( + f"/cloud/v1/snapshots/{project_id}/{region_id}/{snapshot_id}", + body=maybe_transform( + { + "name": name, + "tags": tags, + }, + volume_snapshot_update_params.VolumeSnapshotUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Snapshot, + ) + + def delete( + self, + snapshot_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a specific snapshot. + + Args: + project_id: Project ID + + region_id: Region ID + + snapshot_id: Unique identifier of the snapshot + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not snapshot_id: + raise ValueError(f"Expected a non-empty value for `snapshot_id` but received {snapshot_id!r}") + return self._delete( + f"/cloud/v1/snapshots/{project_id}/{region_id}/{snapshot_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + snapshot_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Snapshot: + """ + Get detailed information about a specific snapshot. + + Args: + project_id: Project ID + + region_id: Region ID + + snapshot_id: Unique identifier of the snapshot + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not snapshot_id: + raise ValueError(f"Expected a non-empty value for `snapshot_id` but received {snapshot_id!r}") + return self._get( + f"/cloud/v1/snapshots/{project_id}/{region_id}/{snapshot_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Snapshot, + ) + + +class AsyncVolumeSnapshotsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncVolumeSnapshotsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncVolumeSnapshotsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncVolumeSnapshotsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncVolumeSnapshotsResourceWithStreamingResponse(self) + + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + volume_id: str, + description: str | Omit = omit, + tags: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Create a new snapshot from a volume. + + Args: + name: Snapshot name + + volume_id: Volume ID to make snapshot of + + description: Snapshot description + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/snapshots/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "name": name, + "volume_id": volume_id, + "description": description, + "tags": tags, + }, + volume_snapshot_create_params.VolumeSnapshotCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + snapshot_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Snapshot: + """ + Rename snapshot or update tags. + + Args: + project_id: Project ID + + region_id: Region ID + + snapshot_id: Unique identifier of the snapshot + + name: Display name for the snapshot (3-63 chars). Used in customer portal and API. + Does not affect snapshot data. + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not snapshot_id: + raise ValueError(f"Expected a non-empty value for `snapshot_id` but received {snapshot_id!r}") + return await self._patch( + f"/cloud/v1/snapshots/{project_id}/{region_id}/{snapshot_id}", + body=await async_maybe_transform( + { + "name": name, + "tags": tags, + }, + volume_snapshot_update_params.VolumeSnapshotUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Snapshot, + ) + + async def delete( + self, + snapshot_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Delete a specific snapshot. + + Args: + project_id: Project ID + + region_id: Region ID + + snapshot_id: Unique identifier of the snapshot + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not snapshot_id: + raise ValueError(f"Expected a non-empty value for `snapshot_id` but received {snapshot_id!r}") + return await self._delete( + f"/cloud/v1/snapshots/{project_id}/{region_id}/{snapshot_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + snapshot_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Snapshot: + """ + Get detailed information about a specific snapshot. + + Args: + project_id: Project ID + + region_id: Region ID + + snapshot_id: Unique identifier of the snapshot + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not snapshot_id: + raise ValueError(f"Expected a non-empty value for `snapshot_id` but received {snapshot_id!r}") + return await self._get( + f"/cloud/v1/snapshots/{project_id}/{region_id}/{snapshot_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Snapshot, + ) + + +class VolumeSnapshotsResourceWithRawResponse: + def __init__(self, volume_snapshots: VolumeSnapshotsResource) -> None: + self._volume_snapshots = volume_snapshots + + self.create = to_raw_response_wrapper( + volume_snapshots.create, + ) + self.update = to_raw_response_wrapper( + volume_snapshots.update, + ) + self.delete = to_raw_response_wrapper( + volume_snapshots.delete, + ) + self.get = to_raw_response_wrapper( + volume_snapshots.get, + ) + + +class AsyncVolumeSnapshotsResourceWithRawResponse: + def __init__(self, volume_snapshots: AsyncVolumeSnapshotsResource) -> None: + self._volume_snapshots = volume_snapshots + + self.create = async_to_raw_response_wrapper( + volume_snapshots.create, + ) + self.update = async_to_raw_response_wrapper( + volume_snapshots.update, + ) + self.delete = async_to_raw_response_wrapper( + volume_snapshots.delete, + ) + self.get = async_to_raw_response_wrapper( + volume_snapshots.get, + ) + + +class VolumeSnapshotsResourceWithStreamingResponse: + def __init__(self, volume_snapshots: VolumeSnapshotsResource) -> None: + self._volume_snapshots = volume_snapshots + + self.create = to_streamed_response_wrapper( + volume_snapshots.create, + ) + self.update = to_streamed_response_wrapper( + volume_snapshots.update, + ) + self.delete = to_streamed_response_wrapper( + volume_snapshots.delete, + ) + self.get = to_streamed_response_wrapper( + volume_snapshots.get, + ) + + +class AsyncVolumeSnapshotsResourceWithStreamingResponse: + def __init__(self, volume_snapshots: AsyncVolumeSnapshotsResource) -> None: + self._volume_snapshots = volume_snapshots + + self.create = async_to_streamed_response_wrapper( + volume_snapshots.create, + ) + self.update = async_to_streamed_response_wrapper( + volume_snapshots.update, + ) + self.delete = async_to_streamed_response_wrapper( + volume_snapshots.delete, + ) + self.get = async_to_streamed_response_wrapper( + volume_snapshots.get, + ) diff --git a/src/gcore/resources/cloud/volumes.py b/src/gcore/resources/cloud/volumes.py new file mode 100644 index 00000000..49020290 --- /dev/null +++ b/src/gcore/resources/cloud/volumes.py @@ -0,0 +1,1802 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, overload + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import required_args, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ...types.cloud import ( + volume_list_params, + volume_create_params, + volume_delete_params, + volume_resize_params, + volume_update_params, + volume_change_type_params, + volume_attach_to_instance_params, + volume_detach_from_instance_params, +) +from ..._base_client import AsyncPaginator, make_request_options +from ...types.cloud.volume import Volume +from ...types.cloud.task_id_list import TaskIDList +from ...types.cloud.tag_update_map_param import TagUpdateMapParam + +__all__ = ["VolumesResource", "AsyncVolumesResource"] + + +class VolumesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> VolumesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return VolumesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> VolumesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return VolumesResourceWithStreamingResponse(self) + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + image_id: str, + name: str, + size: int, + source: Literal["image"], + attachment_tag: str | Omit = omit, + instance_id_to_attach_to: str | Omit = omit, + lifecycle_policy_ids: Iterable[int] | Omit = omit, + tags: TagUpdateMapParam | Omit = omit, + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Create a new volume in the project and region. + + The volume can be created from + scratch, from an image, or from a snapshot. Optionally attach the volume to an + instance during creation. + + Args: + project_id: Project ID + + region_id: Region ID + + image_id: Image ID + + name: Volume name + + size: Volume size in GiB + + source: Volume source type + + attachment_tag: Block device attachment tag (not exposed in the user tags). Only used in + conjunction with `instance_id_to_attach_to` + + instance_id_to_attach_to: `instance_id` to attach newly-created volume to + + lifecycle_policy_ids: List of lifecycle policy IDs (snapshot creation schedules) to associate with the + volume + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + type_name: Volume type. Defaults to `standard`. If not specified for source `snapshot`, + volume type will be derived from the snapshot volume. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + snapshot_id: str, + source: Literal["snapshot"], + attachment_tag: str | Omit = omit, + instance_id_to_attach_to: str | Omit = omit, + lifecycle_policy_ids: Iterable[int] | Omit = omit, + size: int | Omit = omit, + tags: TagUpdateMapParam | Omit = omit, + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Create a new volume in the project and region. + + The volume can be created from + scratch, from an image, or from a snapshot. Optionally attach the volume to an + instance during creation. + + Args: + project_id: Project ID + + region_id: Region ID + + name: Volume name + + snapshot_id: Snapshot ID + + source: Volume source type + + attachment_tag: Block device attachment tag (not exposed in the user tags). Only used in + conjunction with `instance_id_to_attach_to` + + instance_id_to_attach_to: `instance_id` to attach newly-created volume to + + lifecycle_policy_ids: List of lifecycle policy IDs (snapshot creation schedules) to associate with the + volume + + size: Volume size in GiB. If specified, value must be equal to respective snapshot + size + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + type_name: Volume type. Defaults to `standard`. If not specified for source `snapshot`, + volume type will be derived from the snapshot volume. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + size: int, + source: Literal["new-volume"], + attachment_tag: str | Omit = omit, + instance_id_to_attach_to: str | Omit = omit, + lifecycle_policy_ids: Iterable[int] | Omit = omit, + tags: TagUpdateMapParam | Omit = omit, + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Create a new volume in the project and region. + + The volume can be created from + scratch, from an image, or from a snapshot. Optionally attach the volume to an + instance during creation. + + Args: + project_id: Project ID + + region_id: Region ID + + name: Volume name + + size: Volume size in GiB + + source: Volume source type + + attachment_tag: Block device attachment tag (not exposed in the user tags). Only used in + conjunction with `instance_id_to_attach_to` + + instance_id_to_attach_to: `instance_id` to attach newly-created volume to + + lifecycle_policy_ids: List of lifecycle policy IDs (snapshot creation schedules) to associate with the + volume + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + type_name: Volume type. Defaults to `standard`. If not specified for source `snapshot`, + volume type will be derived from the snapshot volume. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args( + ["image_id", "name", "size", "source"], ["name", "snapshot_id", "source"], ["name", "size", "source"] + ) + def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + image_id: str | Omit = omit, + name: str, + size: int | Omit = omit, + source: Literal["image"] | Literal["snapshot"] | Literal["new-volume"], + attachment_tag: str | Omit = omit, + instance_id_to_attach_to: str | Omit = omit, + lifecycle_policy_ids: Iterable[int] | Omit = omit, + tags: TagUpdateMapParam | Omit = omit, + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, + snapshot_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._post( + f"/cloud/v1/volumes/{project_id}/{region_id}", + body=maybe_transform( + { + "image_id": image_id, + "name": name, + "size": size, + "source": source, + "attachment_tag": attachment_tag, + "instance_id_to_attach_to": instance_id_to_attach_to, + "lifecycle_policy_ids": lifecycle_policy_ids, + "tags": tags, + "type_name": type_name, + "snapshot_id": snapshot_id, + }, + volume_create_params.VolumeCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def update( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Volume: + """ + Rename a volume or update tags + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + name: Name + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return self._patch( + f"/cloud/v1/volumes/{project_id}/{region_id}/{volume_id}", + body=maybe_transform( + { + "name": name, + "tags": tags, + }, + volume_update_params.VolumeUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Volume, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + bootable: bool | Omit = omit, + cluster_id: str | Omit = omit, + has_attachments: bool | Omit = omit, + id_part: str | Omit = omit, + instance_id: str | Omit = omit, + limit: int | Omit = omit, + name_part: str | Omit = omit, + offset: int | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[Volume]: + """Retrieve a list of volumes in the project and region. + + The list can be filtered + by various parameters like bootable status, metadata/tags, attachments, instance + ID, name, and ID. + + Args: + project_id: Project ID + + region_id: Region ID + + bootable: Filter by bootable field + + cluster_id: Filter volumes by k8s cluster ID + + has_attachments: Filter by the presence of attachments + + id_part: Filter the volume list result by the ID part of the volume + + instance_id: Filter volumes by instance ID + + limit: Optional. Limit the number of returned items + + name_part: Filter volumes by `name_part` inclusion in volume name.Any substring can be used + and volumes will be returned with names containing the substring. + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + tag_key: Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2 + + tag_key_value: Optional. Filter by tag key-value pairs. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/volumes/{project_id}/{region_id}", + page=SyncOffsetPage[Volume], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "bootable": bootable, + "cluster_id": cluster_id, + "has_attachments": has_attachments, + "id_part": id_part, + "instance_id": instance_id, + "limit": limit, + "name_part": name_part, + "offset": offset, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + }, + volume_list_params.VolumeListParams, + ), + ), + model=Volume, + ) + + def delete( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + snapshots: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Delete a volume and all its snapshots. + + The volume must be in an available state + to be deleted. + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + snapshots: Comma separated list of snapshot IDs to be deleted with the volume. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return self._delete( + f"/cloud/v1/volumes/{project_id}/{region_id}/{volume_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"snapshots": snapshots}, volume_delete_params.VolumeDeleteParams), + ), + cast_to=TaskIDList, + ) + + def attach_to_instance( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + instance_id: str, + attachment_tag: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Attach the volume to instance. + + Note: ultra volume can only be attached to an + instance with shared flavor + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + instance_id: Instance ID. + + attachment_tag: Block device attachment tag (not exposed in the normal tags). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return self._post( + f"/cloud/v2/volumes/{project_id}/{region_id}/{volume_id}/attach", + body=maybe_transform( + { + "instance_id": instance_id, + "attachment_tag": attachment_tag, + }, + volume_attach_to_instance_params.VolumeAttachToInstanceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def change_type( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + volume_type: Literal["ssd_hiiops", "standard"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Volume: + """Change the type of a volume. + + The volume must not have any snapshots to change + its type. + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + volume_type: New volume type name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return self._post( + f"/cloud/v1/volumes/{project_id}/{region_id}/{volume_id}/retype", + body=maybe_transform({"volume_type": volume_type}, volume_change_type_params.VolumeChangeTypeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Volume, + ) + + def detach_from_instance( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + instance_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Detach the volume from instance + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + instance_id: Instance ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return self._post( + f"/cloud/v2/volumes/{project_id}/{region_id}/{volume_id}/detach", + body=maybe_transform( + {"instance_id": instance_id}, volume_detach_from_instance_params.VolumeDetachFromInstanceParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def get( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Volume: + """ + Retrieve detailed information about a specific volume. + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return self._get( + f"/cloud/v1/volumes/{project_id}/{region_id}/{volume_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Volume, + ) + + def resize( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + size: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Increase the size of a volume. + + The new size must be greater than the current + size. + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + size: New volume size in GiB + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return self._post( + f"/cloud/v1/volumes/{project_id}/{region_id}/{volume_id}/extend", + body=maybe_transform({"size": size}, volume_resize_params.VolumeResizeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + def revert_to_last_snapshot( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Revert a volume to its last snapshot. + + The volume must be in an available state + to be reverted. + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/cloud/v1/volumes/{project_id}/{region_id}/{volume_id}/revert", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncVolumesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncVolumesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncVolumesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncVolumesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncVolumesResourceWithStreamingResponse(self) + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + image_id: str, + name: str, + size: int, + source: Literal["image"], + attachment_tag: str | Omit = omit, + instance_id_to_attach_to: str | Omit = omit, + lifecycle_policy_ids: Iterable[int] | Omit = omit, + tags: TagUpdateMapParam | Omit = omit, + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Create a new volume in the project and region. + + The volume can be created from + scratch, from an image, or from a snapshot. Optionally attach the volume to an + instance during creation. + + Args: + project_id: Project ID + + region_id: Region ID + + image_id: Image ID + + name: Volume name + + size: Volume size in GiB + + source: Volume source type + + attachment_tag: Block device attachment tag (not exposed in the user tags). Only used in + conjunction with `instance_id_to_attach_to` + + instance_id_to_attach_to: `instance_id` to attach newly-created volume to + + lifecycle_policy_ids: List of lifecycle policy IDs (snapshot creation schedules) to associate with the + volume + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + type_name: Volume type. Defaults to `standard`. If not specified for source `snapshot`, + volume type will be derived from the snapshot volume. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + snapshot_id: str, + source: Literal["snapshot"], + attachment_tag: str | Omit = omit, + instance_id_to_attach_to: str | Omit = omit, + lifecycle_policy_ids: Iterable[int] | Omit = omit, + size: int | Omit = omit, + tags: TagUpdateMapParam | Omit = omit, + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Create a new volume in the project and region. + + The volume can be created from + scratch, from an image, or from a snapshot. Optionally attach the volume to an + instance during creation. + + Args: + project_id: Project ID + + region_id: Region ID + + name: Volume name + + snapshot_id: Snapshot ID + + source: Volume source type + + attachment_tag: Block device attachment tag (not exposed in the user tags). Only used in + conjunction with `instance_id_to_attach_to` + + instance_id_to_attach_to: `instance_id` to attach newly-created volume to + + lifecycle_policy_ids: List of lifecycle policy IDs (snapshot creation schedules) to associate with the + volume + + size: Volume size in GiB. If specified, value must be equal to respective snapshot + size + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + type_name: Volume type. Defaults to `standard`. If not specified for source `snapshot`, + volume type will be derived from the snapshot volume. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + size: int, + source: Literal["new-volume"], + attachment_tag: str | Omit = omit, + instance_id_to_attach_to: str | Omit = omit, + lifecycle_policy_ids: Iterable[int] | Omit = omit, + tags: TagUpdateMapParam | Omit = omit, + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Create a new volume in the project and region. + + The volume can be created from + scratch, from an image, or from a snapshot. Optionally attach the volume to an + instance during creation. + + Args: + project_id: Project ID + + region_id: Region ID + + name: Volume name + + size: Volume size in GiB + + source: Volume source type + + attachment_tag: Block device attachment tag (not exposed in the user tags). Only used in + conjunction with `instance_id_to_attach_to` + + instance_id_to_attach_to: `instance_id` to attach newly-created volume to + + lifecycle_policy_ids: List of lifecycle policy IDs (snapshot creation schedules) to associate with the + volume + + tags: Key-value tags to associate with the resource. A tag is a key-value pair that + can be associated with a resource, enabling efficient filtering and grouping for + better organization and management. Both tag keys and values have a maximum + length of 255 characters. Some tags are read-only and cannot be modified by the + user. Tags are also integrated with cost reports, allowing cost data to be + filtered based on tag keys or values. + + type_name: Volume type. Defaults to `standard`. If not specified for source `snapshot`, + volume type will be derived from the snapshot volume. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args( + ["image_id", "name", "size", "source"], ["name", "snapshot_id", "source"], ["name", "size", "source"] + ) + async def create( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + image_id: str | Omit = omit, + name: str, + size: int | Omit = omit, + source: Literal["image"] | Literal["snapshot"] | Literal["new-volume"], + attachment_tag: str | Omit = omit, + instance_id_to_attach_to: str | Omit = omit, + lifecycle_policy_ids: Iterable[int] | Omit = omit, + tags: TagUpdateMapParam | Omit = omit, + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] | Omit = omit, + snapshot_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return await self._post( + f"/cloud/v1/volumes/{project_id}/{region_id}", + body=await async_maybe_transform( + { + "image_id": image_id, + "name": name, + "size": size, + "source": source, + "attachment_tag": attachment_tag, + "instance_id_to_attach_to": instance_id_to_attach_to, + "lifecycle_policy_ids": lifecycle_policy_ids, + "tags": tags, + "type_name": type_name, + "snapshot_id": snapshot_id, + }, + volume_create_params.VolumeCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def update( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str | Omit = omit, + tags: Optional[TagUpdateMapParam] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Volume: + """ + Rename a volume or update tags + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + name: Name + + tags: Update key-value tags using JSON Merge Patch semantics (RFC 7386). Provide + key-value pairs to add or update tags. Set tag values to `null` to remove tags. + Unspecified tags remain unchanged. Read-only tags are always preserved and + cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return await self._patch( + f"/cloud/v1/volumes/{project_id}/{region_id}/{volume_id}", + body=await async_maybe_transform( + { + "name": name, + "tags": tags, + }, + volume_update_params.VolumeUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Volume, + ) + + def list( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + bootable: bool | Omit = omit, + cluster_id: str | Omit = omit, + has_attachments: bool | Omit = omit, + id_part: str | Omit = omit, + instance_id: str | Omit = omit, + limit: int | Omit = omit, + name_part: str | Omit = omit, + offset: int | Omit = omit, + tag_key: SequenceNotStr[str] | Omit = omit, + tag_key_value: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Volume, AsyncOffsetPage[Volume]]: + """Retrieve a list of volumes in the project and region. + + The list can be filtered + by various parameters like bootable status, metadata/tags, attachments, instance + ID, name, and ID. + + Args: + project_id: Project ID + + region_id: Region ID + + bootable: Filter by bootable field + + cluster_id: Filter volumes by k8s cluster ID + + has_attachments: Filter by the presence of attachments + + id_part: Filter the volume list result by the ID part of the volume + + instance_id: Filter volumes by instance ID + + limit: Optional. Limit the number of returned items + + name_part: Filter volumes by `name_part` inclusion in volume name.Any substring can be used + and volumes will be returned with names containing the substring. + + offset: Optional. Offset value is used to exclude the first set of records from the + result + + tag_key: Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2 + + tag_key_value: Optional. Filter by tag key-value pairs. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + return self._get_api_list( + f"/cloud/v1/volumes/{project_id}/{region_id}", + page=AsyncOffsetPage[Volume], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "bootable": bootable, + "cluster_id": cluster_id, + "has_attachments": has_attachments, + "id_part": id_part, + "instance_id": instance_id, + "limit": limit, + "name_part": name_part, + "offset": offset, + "tag_key": tag_key, + "tag_key_value": tag_key_value, + }, + volume_list_params.VolumeListParams, + ), + ), + model=Volume, + ) + + async def delete( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + snapshots: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Delete a volume and all its snapshots. + + The volume must be in an available state + to be deleted. + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + snapshots: Comma separated list of snapshot IDs to be deleted with the volume. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return await self._delete( + f"/cloud/v1/volumes/{project_id}/{region_id}/{volume_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"snapshots": snapshots}, volume_delete_params.VolumeDeleteParams), + ), + cast_to=TaskIDList, + ) + + async def attach_to_instance( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + instance_id: str, + attachment_tag: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Attach the volume to instance. + + Note: ultra volume can only be attached to an + instance with shared flavor + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + instance_id: Instance ID. + + attachment_tag: Block device attachment tag (not exposed in the normal tags). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return await self._post( + f"/cloud/v2/volumes/{project_id}/{region_id}/{volume_id}/attach", + body=await async_maybe_transform( + { + "instance_id": instance_id, + "attachment_tag": attachment_tag, + }, + volume_attach_to_instance_params.VolumeAttachToInstanceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def change_type( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + volume_type: Literal["ssd_hiiops", "standard"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Volume: + """Change the type of a volume. + + The volume must not have any snapshots to change + its type. + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + volume_type: New volume type name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return await self._post( + f"/cloud/v1/volumes/{project_id}/{region_id}/{volume_id}/retype", + body=await async_maybe_transform( + {"volume_type": volume_type}, volume_change_type_params.VolumeChangeTypeParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Volume, + ) + + async def detach_from_instance( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + instance_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """ + Detach the volume from instance + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + instance_id: Instance ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return await self._post( + f"/cloud/v2/volumes/{project_id}/{region_id}/{volume_id}/detach", + body=await async_maybe_transform( + {"instance_id": instance_id}, volume_detach_from_instance_params.VolumeDetachFromInstanceParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def get( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Volume: + """ + Retrieve detailed information about a specific volume. + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return await self._get( + f"/cloud/v1/volumes/{project_id}/{region_id}/{volume_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Volume, + ) + + async def resize( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + size: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TaskIDList: + """Increase the size of a volume. + + The new size must be greater than the current + size. + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + size: New volume size in GiB + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + return await self._post( + f"/cloud/v1/volumes/{project_id}/{region_id}/{volume_id}/extend", + body=await async_maybe_transform({"size": size}, volume_resize_params.VolumeResizeParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + async def revert_to_last_snapshot( + self, + volume_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Revert a volume to its last snapshot. + + The volume must be in an available state + to be reverted. + + Args: + project_id: Project ID + + region_id: Region ID + + volume_id: Volume ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._client._get_cloud_project_id_path_param() + if region_id is None: + region_id = self._client._get_cloud_region_id_path_param() + if not volume_id: + raise ValueError(f"Expected a non-empty value for `volume_id` but received {volume_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/cloud/v1/volumes/{project_id}/{region_id}/{volume_id}/revert", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class VolumesResourceWithRawResponse: + def __init__(self, volumes: VolumesResource) -> None: + self._volumes = volumes + + self.create = to_raw_response_wrapper( + volumes.create, + ) + self.update = to_raw_response_wrapper( + volumes.update, + ) + self.list = to_raw_response_wrapper( + volumes.list, + ) + self.delete = to_raw_response_wrapper( + volumes.delete, + ) + self.attach_to_instance = to_raw_response_wrapper( + volumes.attach_to_instance, + ) + self.change_type = to_raw_response_wrapper( + volumes.change_type, + ) + self.detach_from_instance = to_raw_response_wrapper( + volumes.detach_from_instance, + ) + self.get = to_raw_response_wrapper( + volumes.get, + ) + self.resize = to_raw_response_wrapper( + volumes.resize, + ) + self.revert_to_last_snapshot = to_raw_response_wrapper( + volumes.revert_to_last_snapshot, + ) + + +class AsyncVolumesResourceWithRawResponse: + def __init__(self, volumes: AsyncVolumesResource) -> None: + self._volumes = volumes + + self.create = async_to_raw_response_wrapper( + volumes.create, + ) + self.update = async_to_raw_response_wrapper( + volumes.update, + ) + self.list = async_to_raw_response_wrapper( + volumes.list, + ) + self.delete = async_to_raw_response_wrapper( + volumes.delete, + ) + self.attach_to_instance = async_to_raw_response_wrapper( + volumes.attach_to_instance, + ) + self.change_type = async_to_raw_response_wrapper( + volumes.change_type, + ) + self.detach_from_instance = async_to_raw_response_wrapper( + volumes.detach_from_instance, + ) + self.get = async_to_raw_response_wrapper( + volumes.get, + ) + self.resize = async_to_raw_response_wrapper( + volumes.resize, + ) + self.revert_to_last_snapshot = async_to_raw_response_wrapper( + volumes.revert_to_last_snapshot, + ) + + +class VolumesResourceWithStreamingResponse: + def __init__(self, volumes: VolumesResource) -> None: + self._volumes = volumes + + self.create = to_streamed_response_wrapper( + volumes.create, + ) + self.update = to_streamed_response_wrapper( + volumes.update, + ) + self.list = to_streamed_response_wrapper( + volumes.list, + ) + self.delete = to_streamed_response_wrapper( + volumes.delete, + ) + self.attach_to_instance = to_streamed_response_wrapper( + volumes.attach_to_instance, + ) + self.change_type = to_streamed_response_wrapper( + volumes.change_type, + ) + self.detach_from_instance = to_streamed_response_wrapper( + volumes.detach_from_instance, + ) + self.get = to_streamed_response_wrapper( + volumes.get, + ) + self.resize = to_streamed_response_wrapper( + volumes.resize, + ) + self.revert_to_last_snapshot = to_streamed_response_wrapper( + volumes.revert_to_last_snapshot, + ) + + +class AsyncVolumesResourceWithStreamingResponse: + def __init__(self, volumes: AsyncVolumesResource) -> None: + self._volumes = volumes + + self.create = async_to_streamed_response_wrapper( + volumes.create, + ) + self.update = async_to_streamed_response_wrapper( + volumes.update, + ) + self.list = async_to_streamed_response_wrapper( + volumes.list, + ) + self.delete = async_to_streamed_response_wrapper( + volumes.delete, + ) + self.attach_to_instance = async_to_streamed_response_wrapper( + volumes.attach_to_instance, + ) + self.change_type = async_to_streamed_response_wrapper( + volumes.change_type, + ) + self.detach_from_instance = async_to_streamed_response_wrapper( + volumes.detach_from_instance, + ) + self.get = async_to_streamed_response_wrapper( + volumes.get, + ) + self.resize = async_to_streamed_response_wrapper( + volumes.resize, + ) + self.revert_to_last_snapshot = async_to_streamed_response_wrapper( + volumes.revert_to_last_snapshot, + ) diff --git a/src/gcore/resources/dns/__init__.py b/src/gcore/resources/dns/__init__.py new file mode 100644 index 00000000..878fd4ac --- /dev/null +++ b/src/gcore/resources/dns/__init__.py @@ -0,0 +1,89 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .dns import ( + DNSResource, + AsyncDNSResource, + DNSResourceWithRawResponse, + AsyncDNSResourceWithRawResponse, + DNSResourceWithStreamingResponse, + AsyncDNSResourceWithStreamingResponse, +) +from .zones import ( + ZonesResource, + AsyncZonesResource, + ZonesResourceWithRawResponse, + AsyncZonesResourceWithRawResponse, + ZonesResourceWithStreamingResponse, + AsyncZonesResourceWithStreamingResponse, +) +from .metrics import ( + MetricsResource, + AsyncMetricsResource, + MetricsResourceWithRawResponse, + AsyncMetricsResourceWithRawResponse, + MetricsResourceWithStreamingResponse, + AsyncMetricsResourceWithStreamingResponse, +) +from .pickers import ( + PickersResource, + AsyncPickersResource, + PickersResourceWithRawResponse, + AsyncPickersResourceWithRawResponse, + PickersResourceWithStreamingResponse, + AsyncPickersResourceWithStreamingResponse, +) +from .locations import ( + LocationsResource, + AsyncLocationsResource, + LocationsResourceWithRawResponse, + AsyncLocationsResourceWithRawResponse, + LocationsResourceWithStreamingResponse, + AsyncLocationsResourceWithStreamingResponse, +) +from .network_mappings import ( + NetworkMappingsResource, + AsyncNetworkMappingsResource, + NetworkMappingsResourceWithRawResponse, + AsyncNetworkMappingsResourceWithRawResponse, + NetworkMappingsResourceWithStreamingResponse, + AsyncNetworkMappingsResourceWithStreamingResponse, +) + +__all__ = [ + "LocationsResource", + "AsyncLocationsResource", + "LocationsResourceWithRawResponse", + "AsyncLocationsResourceWithRawResponse", + "LocationsResourceWithStreamingResponse", + "AsyncLocationsResourceWithStreamingResponse", + "MetricsResource", + "AsyncMetricsResource", + "MetricsResourceWithRawResponse", + "AsyncMetricsResourceWithRawResponse", + "MetricsResourceWithStreamingResponse", + "AsyncMetricsResourceWithStreamingResponse", + "PickersResource", + "AsyncPickersResource", + "PickersResourceWithRawResponse", + "AsyncPickersResourceWithRawResponse", + "PickersResourceWithStreamingResponse", + "AsyncPickersResourceWithStreamingResponse", + "ZonesResource", + "AsyncZonesResource", + "ZonesResourceWithRawResponse", + "AsyncZonesResourceWithRawResponse", + "ZonesResourceWithStreamingResponse", + "AsyncZonesResourceWithStreamingResponse", + "NetworkMappingsResource", + "AsyncNetworkMappingsResource", + "NetworkMappingsResourceWithRawResponse", + "AsyncNetworkMappingsResourceWithRawResponse", + "NetworkMappingsResourceWithStreamingResponse", + "AsyncNetworkMappingsResourceWithStreamingResponse", + "DNSResource", + "AsyncDNSResource", + "DNSResourceWithRawResponse", + "AsyncDNSResourceWithRawResponse", + "DNSResourceWithStreamingResponse", + "AsyncDNSResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/dns/api.md b/src/gcore/resources/dns/api.md new file mode 100644 index 00000000..ff89a8bc --- /dev/null +++ b/src/gcore/resources/dns/api.md @@ -0,0 +1,159 @@ +# DNS + +Types: + +```python +from gcore.types.dns import DNSGetAccountOverviewResponse, DNSLookupResponse +``` + +Methods: + +- client.dns.get_account_overview() -> DNSGetAccountOverviewResponse +- client.dns.lookup(\*\*params) -> DNSLookupResponse + +## Locations + +Types: + +```python +from gcore.types.dns import ( + DNSLocationTranslations, + LocationListResponse, + LocationListContinentsResponse, + LocationListCountriesResponse, + LocationListRegionsResponse, +) +``` + +Methods: + +- client.dns.locations.list() -> LocationListResponse +- client.dns.locations.list_continents() -> LocationListContinentsResponse +- client.dns.locations.list_countries() -> LocationListCountriesResponse +- client.dns.locations.list_regions() -> LocationListRegionsResponse + +## Metrics + +Types: + +```python +from gcore.types.dns import MetricListResponse +``` + +Methods: + +- client.dns.metrics.list(\*\*params) -> str + +## Pickers + +Types: + +```python +from gcore.types.dns import DNSLabelName, PickerListResponse +``` + +Methods: + +- client.dns.pickers.list() -> PickerListResponse + +### Presets + +Types: + +```python +from gcore.types.dns.pickers import PresetListResponse +``` + +Methods: + +- client.dns.pickers.presets.list() -> PresetListResponse + +## Zones + +Types: + +```python +from gcore.types.dns import ( + DNSNameServer, + ZoneCreateResponse, + ZoneListResponse, + ZoneCheckDelegationStatusResponse, + ZoneExportResponse, + ZoneGetResponse, + ZoneGetStatisticsResponse, + ZoneImportResponse, +) +``` + +Methods: + +- client.dns.zones.create(\*\*params) -> ZoneCreateResponse +- client.dns.zones.list(\*\*params) -> ZoneListResponse +- client.dns.zones.delete(name) -> object +- client.dns.zones.check_delegation_status(name) -> ZoneCheckDelegationStatusResponse +- client.dns.zones.disable(name) -> object +- client.dns.zones.enable(name) -> object +- client.dns.zones.export(zone_name) -> ZoneExportResponse +- client.dns.zones.get(name) -> ZoneGetResponse +- client.dns.zones.get_statistics(name, \*\*params) -> ZoneGetStatisticsResponse +- client.dns.zones.import\_(zone_name, \*\*params) -> ZoneImportResponse +- client.dns.zones.replace(path_name, \*\*params) -> object + +### Dnssec + +Types: + +```python +from gcore.types.dns.zones import DnssecUpdateResponse, DnssecGetResponse +``` + +Methods: + +- client.dns.zones.dnssec.update(name, \*\*params) -> DnssecUpdateResponse +- client.dns.zones.dnssec.get(name) -> DnssecGetResponse + +### Rrsets + +Types: + +```python +from gcore.types.dns.zones import ( + DNSFailoverLog, + DNSOutputRrset, + RrsetListResponse, + RrsetGetFailoverLogsResponse, +) +``` + +Methods: + +- client.dns.zones.rrsets.create(rrset_type, \*, zone_name, rrset_name, \*\*params) -> DNSOutputRrset +- client.dns.zones.rrsets.list(zone_name, \*\*params) -> RrsetListResponse +- client.dns.zones.rrsets.delete(rrset_type, \*, zone_name, rrset_name) -> object +- client.dns.zones.rrsets.get(rrset_type, \*, zone_name, rrset_name) -> DNSOutputRrset +- client.dns.zones.rrsets.get_failover_logs(rrset_type, \*, zone_name, rrset_name, \*\*params) -> RrsetGetFailoverLogsResponse +- client.dns.zones.rrsets.replace(rrset_type, \*, zone_name, rrset_name, \*\*params) -> DNSOutputRrset + +## NetworkMappings + +Types: + +```python +from gcore.types.dns import ( + DNSMappingEntry, + DNSNetworkMapping, + NetworkMappingCreateResponse, + NetworkMappingListResponse, + NetworkMappingImportResponse, +) +``` + +Methods: + +- client.dns.network_mappings.create(\*\*params) -> NetworkMappingCreateResponse +- client.dns.network_mappings.list(\*\*params) -> NetworkMappingListResponse +- client.dns.network_mappings.delete(id) -> object +- client.dns.network_mappings.get(id) -> DNSNetworkMapping +- client.dns.network_mappings.get_by_name(name) -> DNSNetworkMapping +- client.dns.network*mappings.import*() -> NetworkMappingImportResponse +- client.dns.network_mappings.replace(id, \*\*params) -> object diff --git a/src/gcore/resources/dns/dns.py b/src/gcore/resources/dns/dns.py new file mode 100644 index 00000000..f942957c --- /dev/null +++ b/src/gcore/resources/dns/dns.py @@ -0,0 +1,406 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from .metrics import ( + MetricsResource, + AsyncMetricsResource, + MetricsResourceWithRawResponse, + AsyncMetricsResourceWithRawResponse, + MetricsResourceWithStreamingResponse, + AsyncMetricsResourceWithStreamingResponse, +) +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from .locations import ( + LocationsResource, + AsyncLocationsResource, + LocationsResourceWithRawResponse, + AsyncLocationsResourceWithRawResponse, + LocationsResourceWithStreamingResponse, + AsyncLocationsResourceWithStreamingResponse, +) +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.dns import dns_lookup_params +from .zones.zones import ( + ZonesResource, + AsyncZonesResource, + ZonesResourceWithRawResponse, + AsyncZonesResourceWithRawResponse, + ZonesResourceWithStreamingResponse, + AsyncZonesResourceWithStreamingResponse, +) +from ..._base_client import make_request_options +from .pickers.pickers import ( + PickersResource, + AsyncPickersResource, + PickersResourceWithRawResponse, + AsyncPickersResourceWithRawResponse, + PickersResourceWithStreamingResponse, + AsyncPickersResourceWithStreamingResponse, +) +from .network_mappings import ( + NetworkMappingsResource, + AsyncNetworkMappingsResource, + NetworkMappingsResourceWithRawResponse, + AsyncNetworkMappingsResourceWithRawResponse, + NetworkMappingsResourceWithStreamingResponse, + AsyncNetworkMappingsResourceWithStreamingResponse, +) +from ...types.dns.dns_lookup_response import DNSLookupResponse +from ...types.dns.dns_get_account_overview_response import DNSGetAccountOverviewResponse + +__all__ = ["DNSResource", "AsyncDNSResource"] + + +class DNSResource(SyncAPIResource): + @cached_property + def locations(self) -> LocationsResource: + return LocationsResource(self._client) + + @cached_property + def metrics(self) -> MetricsResource: + return MetricsResource(self._client) + + @cached_property + def pickers(self) -> PickersResource: + return PickersResource(self._client) + + @cached_property + def zones(self) -> ZonesResource: + return ZonesResource(self._client) + + @cached_property + def network_mappings(self) -> NetworkMappingsResource: + return NetworkMappingsResource(self._client) + + @cached_property + def with_raw_response(self) -> DNSResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return DNSResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DNSResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return DNSResourceWithStreamingResponse(self) + + def get_account_overview( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSGetAccountOverviewResponse: + """Get info about client""" + return self._get( + "/dns/v2/platform/info", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DNSGetAccountOverviewResponse, + ) + + def lookup( + self, + *, + name: str | Omit = omit, + request_server: Literal["authoritative_dns", "google", "cloudflare", "open_dns", "quad9", "gcore"] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSLookupResponse: + """ + Get the dns records from a specific domain or ip. + + Args: + name: Domain name + + request_server: Server that will be used as resolver + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/dns/v2/lookup", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "name": name, + "request_server": request_server, + }, + dns_lookup_params.DNSLookupParams, + ), + ), + cast_to=DNSLookupResponse, + ) + + +class AsyncDNSResource(AsyncAPIResource): + @cached_property + def locations(self) -> AsyncLocationsResource: + return AsyncLocationsResource(self._client) + + @cached_property + def metrics(self) -> AsyncMetricsResource: + return AsyncMetricsResource(self._client) + + @cached_property + def pickers(self) -> AsyncPickersResource: + return AsyncPickersResource(self._client) + + @cached_property + def zones(self) -> AsyncZonesResource: + return AsyncZonesResource(self._client) + + @cached_property + def network_mappings(self) -> AsyncNetworkMappingsResource: + return AsyncNetworkMappingsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncDNSResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncDNSResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDNSResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncDNSResourceWithStreamingResponse(self) + + async def get_account_overview( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSGetAccountOverviewResponse: + """Get info about client""" + return await self._get( + "/dns/v2/platform/info", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DNSGetAccountOverviewResponse, + ) + + async def lookup( + self, + *, + name: str | Omit = omit, + request_server: Literal["authoritative_dns", "google", "cloudflare", "open_dns", "quad9", "gcore"] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSLookupResponse: + """ + Get the dns records from a specific domain or ip. + + Args: + name: Domain name + + request_server: Server that will be used as resolver + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/dns/v2/lookup", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "name": name, + "request_server": request_server, + }, + dns_lookup_params.DNSLookupParams, + ), + ), + cast_to=DNSLookupResponse, + ) + + +class DNSResourceWithRawResponse: + def __init__(self, dns: DNSResource) -> None: + self._dns = dns + + self.get_account_overview = to_raw_response_wrapper( + dns.get_account_overview, + ) + self.lookup = to_raw_response_wrapper( + dns.lookup, + ) + + @cached_property + def locations(self) -> LocationsResourceWithRawResponse: + return LocationsResourceWithRawResponse(self._dns.locations) + + @cached_property + def metrics(self) -> MetricsResourceWithRawResponse: + return MetricsResourceWithRawResponse(self._dns.metrics) + + @cached_property + def pickers(self) -> PickersResourceWithRawResponse: + return PickersResourceWithRawResponse(self._dns.pickers) + + @cached_property + def zones(self) -> ZonesResourceWithRawResponse: + return ZonesResourceWithRawResponse(self._dns.zones) + + @cached_property + def network_mappings(self) -> NetworkMappingsResourceWithRawResponse: + return NetworkMappingsResourceWithRawResponse(self._dns.network_mappings) + + +class AsyncDNSResourceWithRawResponse: + def __init__(self, dns: AsyncDNSResource) -> None: + self._dns = dns + + self.get_account_overview = async_to_raw_response_wrapper( + dns.get_account_overview, + ) + self.lookup = async_to_raw_response_wrapper( + dns.lookup, + ) + + @cached_property + def locations(self) -> AsyncLocationsResourceWithRawResponse: + return AsyncLocationsResourceWithRawResponse(self._dns.locations) + + @cached_property + def metrics(self) -> AsyncMetricsResourceWithRawResponse: + return AsyncMetricsResourceWithRawResponse(self._dns.metrics) + + @cached_property + def pickers(self) -> AsyncPickersResourceWithRawResponse: + return AsyncPickersResourceWithRawResponse(self._dns.pickers) + + @cached_property + def zones(self) -> AsyncZonesResourceWithRawResponse: + return AsyncZonesResourceWithRawResponse(self._dns.zones) + + @cached_property + def network_mappings(self) -> AsyncNetworkMappingsResourceWithRawResponse: + return AsyncNetworkMappingsResourceWithRawResponse(self._dns.network_mappings) + + +class DNSResourceWithStreamingResponse: + def __init__(self, dns: DNSResource) -> None: + self._dns = dns + + self.get_account_overview = to_streamed_response_wrapper( + dns.get_account_overview, + ) + self.lookup = to_streamed_response_wrapper( + dns.lookup, + ) + + @cached_property + def locations(self) -> LocationsResourceWithStreamingResponse: + return LocationsResourceWithStreamingResponse(self._dns.locations) + + @cached_property + def metrics(self) -> MetricsResourceWithStreamingResponse: + return MetricsResourceWithStreamingResponse(self._dns.metrics) + + @cached_property + def pickers(self) -> PickersResourceWithStreamingResponse: + return PickersResourceWithStreamingResponse(self._dns.pickers) + + @cached_property + def zones(self) -> ZonesResourceWithStreamingResponse: + return ZonesResourceWithStreamingResponse(self._dns.zones) + + @cached_property + def network_mappings(self) -> NetworkMappingsResourceWithStreamingResponse: + return NetworkMappingsResourceWithStreamingResponse(self._dns.network_mappings) + + +class AsyncDNSResourceWithStreamingResponse: + def __init__(self, dns: AsyncDNSResource) -> None: + self._dns = dns + + self.get_account_overview = async_to_streamed_response_wrapper( + dns.get_account_overview, + ) + self.lookup = async_to_streamed_response_wrapper( + dns.lookup, + ) + + @cached_property + def locations(self) -> AsyncLocationsResourceWithStreamingResponse: + return AsyncLocationsResourceWithStreamingResponse(self._dns.locations) + + @cached_property + def metrics(self) -> AsyncMetricsResourceWithStreamingResponse: + return AsyncMetricsResourceWithStreamingResponse(self._dns.metrics) + + @cached_property + def pickers(self) -> AsyncPickersResourceWithStreamingResponse: + return AsyncPickersResourceWithStreamingResponse(self._dns.pickers) + + @cached_property + def zones(self) -> AsyncZonesResourceWithStreamingResponse: + return AsyncZonesResourceWithStreamingResponse(self._dns.zones) + + @cached_property + def network_mappings(self) -> AsyncNetworkMappingsResourceWithStreamingResponse: + return AsyncNetworkMappingsResourceWithStreamingResponse(self._dns.network_mappings) diff --git a/src/gcore/resources/dns/locations.py b/src/gcore/resources/dns/locations.py new file mode 100644 index 00000000..3b571e04 --- /dev/null +++ b/src/gcore/resources/dns/locations.py @@ -0,0 +1,288 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.dns.location_list_response import LocationListResponse +from ...types.dns.location_list_regions_response import LocationListRegionsResponse +from ...types.dns.location_list_countries_response import LocationListCountriesResponse +from ...types.dns.location_list_continents_response import LocationListContinentsResponse + +__all__ = ["LocationsResource", "AsyncLocationsResource"] + + +class LocationsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> LocationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return LocationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> LocationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return LocationsResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LocationListResponse: + """List of All locations continents/countries/regions.""" + return self._get( + "/dns/v2/locations", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LocationListResponse, + ) + + def list_continents( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LocationListContinentsResponse: + """List of All locations continents.""" + return self._get( + "/dns/v2/locations/continents", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LocationListContinentsResponse, + ) + + def list_countries( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LocationListCountriesResponse: + """List of All locations countries.""" + return self._get( + "/dns/v2/locations/countries", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LocationListCountriesResponse, + ) + + def list_regions( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LocationListRegionsResponse: + """List of All locations regions.""" + return self._get( + "/dns/v2/locations/regions", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LocationListRegionsResponse, + ) + + +class AsyncLocationsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncLocationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncLocationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncLocationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncLocationsResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LocationListResponse: + """List of All locations continents/countries/regions.""" + return await self._get( + "/dns/v2/locations", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LocationListResponse, + ) + + async def list_continents( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LocationListContinentsResponse: + """List of All locations continents.""" + return await self._get( + "/dns/v2/locations/continents", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LocationListContinentsResponse, + ) + + async def list_countries( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LocationListCountriesResponse: + """List of All locations countries.""" + return await self._get( + "/dns/v2/locations/countries", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LocationListCountriesResponse, + ) + + async def list_regions( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> LocationListRegionsResponse: + """List of All locations regions.""" + return await self._get( + "/dns/v2/locations/regions", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=LocationListRegionsResponse, + ) + + +class LocationsResourceWithRawResponse: + def __init__(self, locations: LocationsResource) -> None: + self._locations = locations + + self.list = to_raw_response_wrapper( + locations.list, + ) + self.list_continents = to_raw_response_wrapper( + locations.list_continents, + ) + self.list_countries = to_raw_response_wrapper( + locations.list_countries, + ) + self.list_regions = to_raw_response_wrapper( + locations.list_regions, + ) + + +class AsyncLocationsResourceWithRawResponse: + def __init__(self, locations: AsyncLocationsResource) -> None: + self._locations = locations + + self.list = async_to_raw_response_wrapper( + locations.list, + ) + self.list_continents = async_to_raw_response_wrapper( + locations.list_continents, + ) + self.list_countries = async_to_raw_response_wrapper( + locations.list_countries, + ) + self.list_regions = async_to_raw_response_wrapper( + locations.list_regions, + ) + + +class LocationsResourceWithStreamingResponse: + def __init__(self, locations: LocationsResource) -> None: + self._locations = locations + + self.list = to_streamed_response_wrapper( + locations.list, + ) + self.list_continents = to_streamed_response_wrapper( + locations.list_continents, + ) + self.list_countries = to_streamed_response_wrapper( + locations.list_countries, + ) + self.list_regions = to_streamed_response_wrapper( + locations.list_regions, + ) + + +class AsyncLocationsResourceWithStreamingResponse: + def __init__(self, locations: AsyncLocationsResource) -> None: + self._locations = locations + + self.list = async_to_streamed_response_wrapper( + locations.list, + ) + self.list_continents = async_to_streamed_response_wrapper( + locations.list_continents, + ) + self.list_countries = async_to_streamed_response_wrapper( + locations.list_countries, + ) + self.list_regions = async_to_streamed_response_wrapper( + locations.list_regions, + ) diff --git a/src/gcore/resources/dns/metrics.py b/src/gcore/resources/dns/metrics.py new file mode 100644 index 00000000..918583f4 --- /dev/null +++ b/src/gcore/resources/dns/metrics.py @@ -0,0 +1,214 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.dns import metric_list_params +from ..._base_client import make_request_options + +__all__ = ["MetricsResource", "AsyncMetricsResource"] + + +class MetricsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> MetricsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return MetricsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MetricsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return MetricsResourceWithStreamingResponse(self) + + def list( + self, + *, + client_ids: Iterable[int] | Omit = omit, + zone_names: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> str: + """ + Example of success response: + + ``` + HELP healthcheck_state The `healthcheck_state` metric reflects the state of a specific monitor after conducting a health check + TYPE healthcheck_state gauge + healthcheck_state{client_id="1",monitor_id="431",monitor_locations="us-east-1,us-west-1",monitor_name="test-monitor-1",monitor_type="http",rrset_name="rrset-name1",rrset_type="rrset-type1",zone_name="zone-name1"} 0 + healthcheck_state{client_id="1",monitor_id="4871",monitor_locations="fr-1,fr-2",monitor_name="test-monitor-2",monitor_type="tcp",rrset_name="rrset-name2",rrset_type="rrset-type2",zone_name="zone-name2"} 1 + healthcheck_state{client_id="2",monitor_id="7123",monitor_locations="ua-1,ua-2",monitor_name="test-monitor-3",monitor_type="icmp",rrset_name="rrset-name3",rrset_type="rrset-type3",zone_name="zone-name3"} 0 + ``` + + Args: + client_ids: Admin and technical user can specify `client_id` to get metrics for particular + client. Ignored for client + + zone_names: Admin and technical user can specify `monitor_id` to get metrics for particular + zone. Ignored for client + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "plain/text", **(extra_headers or {})} + return self._get( + "/dns/v2/monitor/metrics", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "client_ids": client_ids, + "zone_names": zone_names, + }, + metric_list_params.MetricListParams, + ), + ), + cast_to=str, + ) + + +class AsyncMetricsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncMetricsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncMetricsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMetricsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncMetricsResourceWithStreamingResponse(self) + + async def list( + self, + *, + client_ids: Iterable[int] | Omit = omit, + zone_names: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> str: + """ + Example of success response: + + ``` + HELP healthcheck_state The `healthcheck_state` metric reflects the state of a specific monitor after conducting a health check + TYPE healthcheck_state gauge + healthcheck_state{client_id="1",monitor_id="431",monitor_locations="us-east-1,us-west-1",monitor_name="test-monitor-1",monitor_type="http",rrset_name="rrset-name1",rrset_type="rrset-type1",zone_name="zone-name1"} 0 + healthcheck_state{client_id="1",monitor_id="4871",monitor_locations="fr-1,fr-2",monitor_name="test-monitor-2",monitor_type="tcp",rrset_name="rrset-name2",rrset_type="rrset-type2",zone_name="zone-name2"} 1 + healthcheck_state{client_id="2",monitor_id="7123",monitor_locations="ua-1,ua-2",monitor_name="test-monitor-3",monitor_type="icmp",rrset_name="rrset-name3",rrset_type="rrset-type3",zone_name="zone-name3"} 0 + ``` + + Args: + client_ids: Admin and technical user can specify `client_id` to get metrics for particular + client. Ignored for client + + zone_names: Admin and technical user can specify `monitor_id` to get metrics for particular + zone. Ignored for client + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "plain/text", **(extra_headers or {})} + return await self._get( + "/dns/v2/monitor/metrics", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "client_ids": client_ids, + "zone_names": zone_names, + }, + metric_list_params.MetricListParams, + ), + ), + cast_to=str, + ) + + +class MetricsResourceWithRawResponse: + def __init__(self, metrics: MetricsResource) -> None: + self._metrics = metrics + + self.list = to_raw_response_wrapper( + metrics.list, + ) + + +class AsyncMetricsResourceWithRawResponse: + def __init__(self, metrics: AsyncMetricsResource) -> None: + self._metrics = metrics + + self.list = async_to_raw_response_wrapper( + metrics.list, + ) + + +class MetricsResourceWithStreamingResponse: + def __init__(self, metrics: MetricsResource) -> None: + self._metrics = metrics + + self.list = to_streamed_response_wrapper( + metrics.list, + ) + + +class AsyncMetricsResourceWithStreamingResponse: + def __init__(self, metrics: AsyncMetricsResource) -> None: + self._metrics = metrics + + self.list = async_to_streamed_response_wrapper( + metrics.list, + ) diff --git a/src/gcore/resources/dns/network_mappings.py b/src/gcore/resources/dns/network_mappings.py new file mode 100644 index 00000000..1feb1047 --- /dev/null +++ b/src/gcore/resources/dns/network_mappings.py @@ -0,0 +1,996 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.dns import network_mapping_list_params, network_mapping_create_params, network_mapping_replace_params +from ..._base_client import make_request_options +from ...types.dns.dns_network_mapping import DNSNetworkMapping +from ...types.dns.dns_mapping_entry_param import DNSMappingEntryParam +from ...types.dns.network_mapping_list_response import NetworkMappingListResponse +from ...types.dns.network_mapping_create_response import NetworkMappingCreateResponse +from ...types.dns.network_mapping_import_response import NetworkMappingImportResponse + +__all__ = ["NetworkMappingsResource", "AsyncNetworkMappingsResource"] + + +class NetworkMappingsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> NetworkMappingsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return NetworkMappingsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> NetworkMappingsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return NetworkMappingsResourceWithStreamingResponse(self) + + def create( + self, + *, + mapping: Iterable[DNSMappingEntryParam] | Omit = omit, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NetworkMappingCreateResponse: + """ + Create new network mapping. + + Example of request: + + ``` + curl --location --request POST 'https://api.gcore.com/dns/v2/network-mappings' \\ + --header 'Authorization: Bearer ...' \\ + --header 'Content-Type: application/json' \\ + --data-raw '{ + "name": "test", + "mapping": [ + { + "tags": [ + "tag1" + ], + "cidr4": [ + "192.0.2.0/24", + "198.0.100.0/24" + ] + }, + { + "tags": [ + "tag2", + "tag3" + ], + "cidr4": [ + "192.1.2.0/24", + "198.1.100.0/24" + ], + "cidr6": [ + "aa:10::/64" + ] + } + ] + }' + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/dns/v2/network-mappings", + body=maybe_transform( + { + "mapping": mapping, + "name": name, + }, + network_mapping_create_params.NetworkMappingCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NetworkMappingCreateResponse, + ) + + def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: str | Omit = omit, + order_direction: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NetworkMappingListResponse: + """ + List of network mappings. + + Example of request: + + ``` + curl --location --request GET 'https://api.gcore.com/dns/v2/network-mappings' \\ + --header 'Authorization: Bearer ...' + ``` + + Args: + limit: Max number of records in response + + offset: Amount of records to skip before beginning to write in response. + + order_by: Field name to sort by + + order_direction: Ascending or descending order + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/dns/v2/network-mappings", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + "order_by": order_by, + "order_direction": order_direction, + }, + network_mapping_list_params.NetworkMappingListParams, + ), + ), + cast_to=NetworkMappingListResponse, + ) + + def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Delete network mapping. + + Example of request: + + ``` + curl --location --request DELETE 'https://api.gcore.com/dns/v2/network-mappings/123' \\ + --header 'Authorization: Bearer ...' + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._delete( + f"/dns/v2/network-mappings/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSNetworkMapping: + """ + Particular network mapping item info + + Example of request: + + ``` + curl --location --request GET 'https://api.gcore.com/dns/v2/network-mappings/123' \\ + --header 'Authorization: Bearer ...' + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/dns/v2/network-mappings/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DNSNetworkMapping, + ) + + def get_by_name( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSNetworkMapping: + """ + Get network mapping by name. + + Particular network mapping item info + + Example of request: + + ``` + curl --location --request GET 'https://api.gcore.com/dns/v2/network-mappings/test-mapping' \\ + --header 'Authorization: Bearer ...' + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return self._get( + f"/dns/v2/network-mappings/{name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DNSNetworkMapping, + ) + + def import_( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NetworkMappingImportResponse: + """ + Import network mapping from YAML file. + + Note: A YAML file use spaces as indentation, tabs are not allowed. Example of + input file: + + ``` + name: mapping_rule_1 + mapping: + - tags: + - tag_name_1 + cidr4: + - 127.0.2.0/24 + - tags: + - tag_name_2 + - tag_name_3 + cidr4: + - 128.0.1.0/24 + - 128.0.2.0/24 + - 128.0.3.0/24 + cidr6: + - ac:20::0/64 + --- + name: mapping_rule_2 + mapping: + - tags: + - my_network + cidr4: + - 129.0.2.0/24 + cidr6: + - ac:20::0/64 + ``` + + Example of request: + + ``` + curl --location --request POST 'https://api.gcore.com/dns/v2/network-mappings/import' \\ + --header 'Authorization: Bearer ...' \\ + --header 'Content-Type: text/plain' \\ + --data-raw 'name: mapping_rule_1 + mapping: + - tags: + - tag_name_1 + cidr4: + - 127.0.2.0/24 + - tags: + - tag_name_2 + - tag_name_3 + cidr4: + - 128.0.1.0/24 + - 128.0.2.0/24 + - 128.0.3.0/24 + cidr6: + - aa:10::/64 + --- + name: mapping_rule_2 + mapping: + - tags: + - my_network + cidr4: + - 129.0.2.0/24 + cidr6: + - ac:20::0/64' + ``` + """ + return self._post( + "/dns/v2/network-mappings/import", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NetworkMappingImportResponse, + ) + + def replace( + self, + id: int, + *, + mapping: Iterable[DNSMappingEntryParam] | Omit = omit, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Update network mapping (Note: name of network mapping cannot be changed) + + Example of request: + + ``` + curl --location --request PUT 'https://api.gcore.com/dns/v2/network-mappings/123' \\ + --header 'Authorization: Bearer ...' \\ + --header 'Content-Type: application/json' \\ + --data-raw '{ + "name": "test-mapping", + "mapping": [ + { + "tags": [ + "tag1" + ], + "cidr4": [ + "192.0.2.0/24" + ] + }, + { + "tags": [ + "tag2", + "tag3" + ], + "cidr4": [ + "192.1.2.0/24" + ], + "cidr6": [ + "aa:10::/64" + ] + } + ] + }' + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/dns/v2/network-mappings/{id}", + body=maybe_transform( + { + "mapping": mapping, + "name": name, + }, + network_mapping_replace_params.NetworkMappingReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncNetworkMappingsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncNetworkMappingsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncNetworkMappingsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncNetworkMappingsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncNetworkMappingsResourceWithStreamingResponse(self) + + async def create( + self, + *, + mapping: Iterable[DNSMappingEntryParam] | Omit = omit, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NetworkMappingCreateResponse: + """ + Create new network mapping. + + Example of request: + + ``` + curl --location --request POST 'https://api.gcore.com/dns/v2/network-mappings' \\ + --header 'Authorization: Bearer ...' \\ + --header 'Content-Type: application/json' \\ + --data-raw '{ + "name": "test", + "mapping": [ + { + "tags": [ + "tag1" + ], + "cidr4": [ + "192.0.2.0/24", + "198.0.100.0/24" + ] + }, + { + "tags": [ + "tag2", + "tag3" + ], + "cidr4": [ + "192.1.2.0/24", + "198.1.100.0/24" + ], + "cidr6": [ + "aa:10::/64" + ] + } + ] + }' + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/dns/v2/network-mappings", + body=await async_maybe_transform( + { + "mapping": mapping, + "name": name, + }, + network_mapping_create_params.NetworkMappingCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NetworkMappingCreateResponse, + ) + + async def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: str | Omit = omit, + order_direction: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NetworkMappingListResponse: + """ + List of network mappings. + + Example of request: + + ``` + curl --location --request GET 'https://api.gcore.com/dns/v2/network-mappings' \\ + --header 'Authorization: Bearer ...' + ``` + + Args: + limit: Max number of records in response + + offset: Amount of records to skip before beginning to write in response. + + order_by: Field name to sort by + + order_direction: Ascending or descending order + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/dns/v2/network-mappings", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "limit": limit, + "offset": offset, + "order_by": order_by, + "order_direction": order_direction, + }, + network_mapping_list_params.NetworkMappingListParams, + ), + ), + cast_to=NetworkMappingListResponse, + ) + + async def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Delete network mapping. + + Example of request: + + ``` + curl --location --request DELETE 'https://api.gcore.com/dns/v2/network-mappings/123' \\ + --header 'Authorization: Bearer ...' + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._delete( + f"/dns/v2/network-mappings/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSNetworkMapping: + """ + Particular network mapping item info + + Example of request: + + ``` + curl --location --request GET 'https://api.gcore.com/dns/v2/network-mappings/123' \\ + --header 'Authorization: Bearer ...' + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/dns/v2/network-mappings/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DNSNetworkMapping, + ) + + async def get_by_name( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSNetworkMapping: + """ + Get network mapping by name. + + Particular network mapping item info + + Example of request: + + ``` + curl --location --request GET 'https://api.gcore.com/dns/v2/network-mappings/test-mapping' \\ + --header 'Authorization: Bearer ...' + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return await self._get( + f"/dns/v2/network-mappings/{name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DNSNetworkMapping, + ) + + async def import_( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NetworkMappingImportResponse: + """ + Import network mapping from YAML file. + + Note: A YAML file use spaces as indentation, tabs are not allowed. Example of + input file: + + ``` + name: mapping_rule_1 + mapping: + - tags: + - tag_name_1 + cidr4: + - 127.0.2.0/24 + - tags: + - tag_name_2 + - tag_name_3 + cidr4: + - 128.0.1.0/24 + - 128.0.2.0/24 + - 128.0.3.0/24 + cidr6: + - ac:20::0/64 + --- + name: mapping_rule_2 + mapping: + - tags: + - my_network + cidr4: + - 129.0.2.0/24 + cidr6: + - ac:20::0/64 + ``` + + Example of request: + + ``` + curl --location --request POST 'https://api.gcore.com/dns/v2/network-mappings/import' \\ + --header 'Authorization: Bearer ...' \\ + --header 'Content-Type: text/plain' \\ + --data-raw 'name: mapping_rule_1 + mapping: + - tags: + - tag_name_1 + cidr4: + - 127.0.2.0/24 + - tags: + - tag_name_2 + - tag_name_3 + cidr4: + - 128.0.1.0/24 + - 128.0.2.0/24 + - 128.0.3.0/24 + cidr6: + - aa:10::/64 + --- + name: mapping_rule_2 + mapping: + - tags: + - my_network + cidr4: + - 129.0.2.0/24 + cidr6: + - ac:20::0/64' + ``` + """ + return await self._post( + "/dns/v2/network-mappings/import", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NetworkMappingImportResponse, + ) + + async def replace( + self, + id: int, + *, + mapping: Iterable[DNSMappingEntryParam] | Omit = omit, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Update network mapping (Note: name of network mapping cannot be changed) + + Example of request: + + ``` + curl --location --request PUT 'https://api.gcore.com/dns/v2/network-mappings/123' \\ + --header 'Authorization: Bearer ...' \\ + --header 'Content-Type: application/json' \\ + --data-raw '{ + "name": "test-mapping", + "mapping": [ + { + "tags": [ + "tag1" + ], + "cidr4": [ + "192.0.2.0/24" + ] + }, + { + "tags": [ + "tag2", + "tag3" + ], + "cidr4": [ + "192.1.2.0/24" + ], + "cidr6": [ + "aa:10::/64" + ] + } + ] + }' + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/dns/v2/network-mappings/{id}", + body=await async_maybe_transform( + { + "mapping": mapping, + "name": name, + }, + network_mapping_replace_params.NetworkMappingReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class NetworkMappingsResourceWithRawResponse: + def __init__(self, network_mappings: NetworkMappingsResource) -> None: + self._network_mappings = network_mappings + + self.create = to_raw_response_wrapper( + network_mappings.create, + ) + self.list = to_raw_response_wrapper( + network_mappings.list, + ) + self.delete = to_raw_response_wrapper( + network_mappings.delete, + ) + self.get = to_raw_response_wrapper( + network_mappings.get, + ) + self.get_by_name = to_raw_response_wrapper( + network_mappings.get_by_name, + ) + self.import_ = to_raw_response_wrapper( + network_mappings.import_, + ) + self.replace = to_raw_response_wrapper( + network_mappings.replace, + ) + + +class AsyncNetworkMappingsResourceWithRawResponse: + def __init__(self, network_mappings: AsyncNetworkMappingsResource) -> None: + self._network_mappings = network_mappings + + self.create = async_to_raw_response_wrapper( + network_mappings.create, + ) + self.list = async_to_raw_response_wrapper( + network_mappings.list, + ) + self.delete = async_to_raw_response_wrapper( + network_mappings.delete, + ) + self.get = async_to_raw_response_wrapper( + network_mappings.get, + ) + self.get_by_name = async_to_raw_response_wrapper( + network_mappings.get_by_name, + ) + self.import_ = async_to_raw_response_wrapper( + network_mappings.import_, + ) + self.replace = async_to_raw_response_wrapper( + network_mappings.replace, + ) + + +class NetworkMappingsResourceWithStreamingResponse: + def __init__(self, network_mappings: NetworkMappingsResource) -> None: + self._network_mappings = network_mappings + + self.create = to_streamed_response_wrapper( + network_mappings.create, + ) + self.list = to_streamed_response_wrapper( + network_mappings.list, + ) + self.delete = to_streamed_response_wrapper( + network_mappings.delete, + ) + self.get = to_streamed_response_wrapper( + network_mappings.get, + ) + self.get_by_name = to_streamed_response_wrapper( + network_mappings.get_by_name, + ) + self.import_ = to_streamed_response_wrapper( + network_mappings.import_, + ) + self.replace = to_streamed_response_wrapper( + network_mappings.replace, + ) + + +class AsyncNetworkMappingsResourceWithStreamingResponse: + def __init__(self, network_mappings: AsyncNetworkMappingsResource) -> None: + self._network_mappings = network_mappings + + self.create = async_to_streamed_response_wrapper( + network_mappings.create, + ) + self.list = async_to_streamed_response_wrapper( + network_mappings.list, + ) + self.delete = async_to_streamed_response_wrapper( + network_mappings.delete, + ) + self.get = async_to_streamed_response_wrapper( + network_mappings.get, + ) + self.get_by_name = async_to_streamed_response_wrapper( + network_mappings.get_by_name, + ) + self.import_ = async_to_streamed_response_wrapper( + network_mappings.import_, + ) + self.replace = async_to_streamed_response_wrapper( + network_mappings.replace, + ) diff --git a/src/gcore/resources/dns/pickers/__init__.py b/src/gcore/resources/dns/pickers/__init__.py new file mode 100644 index 00000000..27d063d8 --- /dev/null +++ b/src/gcore/resources/dns/pickers/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .pickers import ( + PickersResource, + AsyncPickersResource, + PickersResourceWithRawResponse, + AsyncPickersResourceWithRawResponse, + PickersResourceWithStreamingResponse, + AsyncPickersResourceWithStreamingResponse, +) +from .presets import ( + PresetsResource, + AsyncPresetsResource, + PresetsResourceWithRawResponse, + AsyncPresetsResourceWithRawResponse, + PresetsResourceWithStreamingResponse, + AsyncPresetsResourceWithStreamingResponse, +) + +__all__ = [ + "PresetsResource", + "AsyncPresetsResource", + "PresetsResourceWithRawResponse", + "AsyncPresetsResourceWithRawResponse", + "PresetsResourceWithStreamingResponse", + "AsyncPresetsResourceWithStreamingResponse", + "PickersResource", + "AsyncPickersResource", + "PickersResourceWithRawResponse", + "AsyncPickersResourceWithRawResponse", + "PickersResourceWithStreamingResponse", + "AsyncPickersResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/dns/pickers/pickers.py b/src/gcore/resources/dns/pickers/pickers.py new file mode 100644 index 00000000..c08f6586 --- /dev/null +++ b/src/gcore/resources/dns/pickers/pickers.py @@ -0,0 +1,167 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .presets import ( + PresetsResource, + AsyncPresetsResource, + PresetsResourceWithRawResponse, + AsyncPresetsResourceWithRawResponse, + PresetsResourceWithStreamingResponse, + AsyncPresetsResourceWithStreamingResponse, +) +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.dns.picker_list_response import PickerListResponse + +__all__ = ["PickersResource", "AsyncPickersResource"] + + +class PickersResource(SyncAPIResource): + @cached_property + def presets(self) -> PresetsResource: + return PresetsResource(self._client) + + @cached_property + def with_raw_response(self) -> PickersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return PickersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PickersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return PickersResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PickerListResponse: + """Returns list of picker""" + return self._get( + "/dns/v2/pickers", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PickerListResponse, + ) + + +class AsyncPickersResource(AsyncAPIResource): + @cached_property + def presets(self) -> AsyncPresetsResource: + return AsyncPresetsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncPickersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncPickersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPickersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncPickersResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PickerListResponse: + """Returns list of picker""" + return await self._get( + "/dns/v2/pickers", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PickerListResponse, + ) + + +class PickersResourceWithRawResponse: + def __init__(self, pickers: PickersResource) -> None: + self._pickers = pickers + + self.list = to_raw_response_wrapper( + pickers.list, + ) + + @cached_property + def presets(self) -> PresetsResourceWithRawResponse: + return PresetsResourceWithRawResponse(self._pickers.presets) + + +class AsyncPickersResourceWithRawResponse: + def __init__(self, pickers: AsyncPickersResource) -> None: + self._pickers = pickers + + self.list = async_to_raw_response_wrapper( + pickers.list, + ) + + @cached_property + def presets(self) -> AsyncPresetsResourceWithRawResponse: + return AsyncPresetsResourceWithRawResponse(self._pickers.presets) + + +class PickersResourceWithStreamingResponse: + def __init__(self, pickers: PickersResource) -> None: + self._pickers = pickers + + self.list = to_streamed_response_wrapper( + pickers.list, + ) + + @cached_property + def presets(self) -> PresetsResourceWithStreamingResponse: + return PresetsResourceWithStreamingResponse(self._pickers.presets) + + +class AsyncPickersResourceWithStreamingResponse: + def __init__(self, pickers: AsyncPickersResource) -> None: + self._pickers = pickers + + self.list = async_to_streamed_response_wrapper( + pickers.list, + ) + + @cached_property + def presets(self) -> AsyncPresetsResourceWithStreamingResponse: + return AsyncPresetsResourceWithStreamingResponse(self._pickers.presets) diff --git a/src/gcore/resources/dns/pickers/presets.py b/src/gcore/resources/dns/pickers/presets.py new file mode 100644 index 00000000..a816c8cc --- /dev/null +++ b/src/gcore/resources/dns/pickers/presets.py @@ -0,0 +1,135 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.dns.pickers.preset_list_response import PresetListResponse + +__all__ = ["PresetsResource", "AsyncPresetsResource"] + + +class PresetsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> PresetsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return PresetsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PresetsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return PresetsResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PresetListResponse: + """Returns list of picker preset""" + return self._get( + "/dns/v2/pickers/presets", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PresetListResponse, + ) + + +class AsyncPresetsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncPresetsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncPresetsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPresetsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncPresetsResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PresetListResponse: + """Returns list of picker preset""" + return await self._get( + "/dns/v2/pickers/presets", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PresetListResponse, + ) + + +class PresetsResourceWithRawResponse: + def __init__(self, presets: PresetsResource) -> None: + self._presets = presets + + self.list = to_raw_response_wrapper( + presets.list, + ) + + +class AsyncPresetsResourceWithRawResponse: + def __init__(self, presets: AsyncPresetsResource) -> None: + self._presets = presets + + self.list = async_to_raw_response_wrapper( + presets.list, + ) + + +class PresetsResourceWithStreamingResponse: + def __init__(self, presets: PresetsResource) -> None: + self._presets = presets + + self.list = to_streamed_response_wrapper( + presets.list, + ) + + +class AsyncPresetsResourceWithStreamingResponse: + def __init__(self, presets: AsyncPresetsResource) -> None: + self._presets = presets + + self.list = async_to_streamed_response_wrapper( + presets.list, + ) diff --git a/src/gcore/resources/dns/zones/__init__.py b/src/gcore/resources/dns/zones/__init__.py new file mode 100644 index 00000000..056d22ea --- /dev/null +++ b/src/gcore/resources/dns/zones/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .zones import ( + ZonesResource, + AsyncZonesResource, + ZonesResourceWithRawResponse, + AsyncZonesResourceWithRawResponse, + ZonesResourceWithStreamingResponse, + AsyncZonesResourceWithStreamingResponse, +) +from .dnssec import ( + DnssecResource, + AsyncDnssecResource, + DnssecResourceWithRawResponse, + AsyncDnssecResourceWithRawResponse, + DnssecResourceWithStreamingResponse, + AsyncDnssecResourceWithStreamingResponse, +) +from .rrsets import ( + RrsetsResource, + AsyncRrsetsResource, + RrsetsResourceWithRawResponse, + AsyncRrsetsResourceWithRawResponse, + RrsetsResourceWithStreamingResponse, + AsyncRrsetsResourceWithStreamingResponse, +) + +__all__ = [ + "DnssecResource", + "AsyncDnssecResource", + "DnssecResourceWithRawResponse", + "AsyncDnssecResourceWithRawResponse", + "DnssecResourceWithStreamingResponse", + "AsyncDnssecResourceWithStreamingResponse", + "RrsetsResource", + "AsyncRrsetsResource", + "RrsetsResourceWithRawResponse", + "AsyncRrsetsResourceWithRawResponse", + "RrsetsResourceWithStreamingResponse", + "AsyncRrsetsResourceWithStreamingResponse", + "ZonesResource", + "AsyncZonesResource", + "ZonesResourceWithRawResponse", + "AsyncZonesResourceWithRawResponse", + "ZonesResourceWithStreamingResponse", + "AsyncZonesResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/dns/zones/dnssec.py b/src/gcore/resources/dns/zones/dnssec.py new file mode 100644 index 00000000..e91a9d09 --- /dev/null +++ b/src/gcore/resources/dns/zones/dnssec.py @@ -0,0 +1,248 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.dns.zones import dnssec_update_params +from ....types.dns.zones.dnssec_get_response import DnssecGetResponse +from ....types.dns.zones.dnssec_update_response import DnssecUpdateResponse + +__all__ = ["DnssecResource", "AsyncDnssecResource"] + + +class DnssecResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DnssecResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return DnssecResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DnssecResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return DnssecResourceWithStreamingResponse(self) + + def update( + self, + name: str, + *, + enabled: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DnssecUpdateResponse: + """ + Enable or disable DNSSEC for a DNS zone. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return self._patch( + f"/dns/v2/zones/{name}/dnssec", + body=maybe_transform({"enabled": enabled}, dnssec_update_params.DnssecUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DnssecUpdateResponse, + ) + + def get( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DnssecGetResponse: + """ + Get DNSSEC DS for a DNS zone. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return self._get( + f"/dns/v2/zones/{name}/dnssec", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DnssecGetResponse, + ) + + +class AsyncDnssecResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDnssecResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncDnssecResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDnssecResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncDnssecResourceWithStreamingResponse(self) + + async def update( + self, + name: str, + *, + enabled: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DnssecUpdateResponse: + """ + Enable or disable DNSSEC for a DNS zone. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return await self._patch( + f"/dns/v2/zones/{name}/dnssec", + body=await async_maybe_transform({"enabled": enabled}, dnssec_update_params.DnssecUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DnssecUpdateResponse, + ) + + async def get( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DnssecGetResponse: + """ + Get DNSSEC DS for a DNS zone. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return await self._get( + f"/dns/v2/zones/{name}/dnssec", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DnssecGetResponse, + ) + + +class DnssecResourceWithRawResponse: + def __init__(self, dnssec: DnssecResource) -> None: + self._dnssec = dnssec + + self.update = to_raw_response_wrapper( + dnssec.update, + ) + self.get = to_raw_response_wrapper( + dnssec.get, + ) + + +class AsyncDnssecResourceWithRawResponse: + def __init__(self, dnssec: AsyncDnssecResource) -> None: + self._dnssec = dnssec + + self.update = async_to_raw_response_wrapper( + dnssec.update, + ) + self.get = async_to_raw_response_wrapper( + dnssec.get, + ) + + +class DnssecResourceWithStreamingResponse: + def __init__(self, dnssec: DnssecResource) -> None: + self._dnssec = dnssec + + self.update = to_streamed_response_wrapper( + dnssec.update, + ) + self.get = to_streamed_response_wrapper( + dnssec.get, + ) + + +class AsyncDnssecResourceWithStreamingResponse: + def __init__(self, dnssec: AsyncDnssecResource) -> None: + self._dnssec = dnssec + + self.update = async_to_streamed_response_wrapper( + dnssec.update, + ) + self.get = async_to_streamed_response_wrapper( + dnssec.get, + ) diff --git a/src/gcore/resources/dns/zones/rrsets.py b/src/gcore/resources/dns/zones/rrsets.py new file mode 100644 index 00000000..736b590d --- /dev/null +++ b/src/gcore/resources/dns/zones/rrsets.py @@ -0,0 +1,989 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.dns.zones import ( + rrset_list_params, + rrset_create_params, + rrset_replace_params, + rrset_get_failover_logs_params, +) +from ....types.dns.zones.dns_output_rrset import DNSOutputRrset +from ....types.dns.zones.rrset_list_response import RrsetListResponse +from ....types.dns.zones.rrset_get_failover_logs_response import RrsetGetFailoverLogsResponse + +__all__ = ["RrsetsResource", "AsyncRrsetsResource"] + + +class RrsetsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RrsetsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return RrsetsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RrsetsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return RrsetsResourceWithStreamingResponse(self) + + def create( + self, + rrset_type: str, + *, + zone_name: str, + rrset_name: str, + resource_records: Iterable[rrset_create_params.ResourceRecord], + meta: Dict[str, object] | Omit = omit, + pickers: Iterable[rrset_create_params.Picker] | Omit = omit, + ttl: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSOutputRrset: + """ + Add the RRSet to the zone specified by zoneName, RRSets can be configured to be + either dynamic or static. + + Static RRsets Staticly configured RRSets provide DNS responses as is. + + Dynamic RRsets Dynamic RRSets have picker configuration defined thus it's + possible to finely customize DNS response. Picking rules are defined on the + RRSet level as a list of selectors, filters and mutators. Picker considers + different resource records metadata, requestor IP, and other event-feeds like + monitoring. Picker configuration is an ordered list defined by "pickers" + attribute. Requestor IP is determined by EDNS Client Subnet (ECS) if defined, + otherwise - by client/recursor IP. Selector pickers are used in the specified + order until the first match, in case of match - all next selectors are bypassed. + Filters or mutators are applied to the match according to the order they are + specified. + + For example, sort records by proximity to user, shuffle based on weights and + return not more than 3: + + `"pickers": [ { "type": "geodistance" }, { "type": "weighted_shuffle" }, { "type": "first_n", "limit": 3 } ]` + + geodns filter A resource record is included in the answer if resource record's + metadata matches requestor info. For each resource record in RRSet, the + following metadata is considered (in the order specified): + + - `ip` - list of network addresses in CIDR format, e.g. + `["192.168.15.150/25", "2003:de:2016::/48"]`; + - `asn` - list of autonomous system numbers, e.g. `[1234, 5678]`; + - `regions` - list of region codes, e.g. `["de-bw", "de-by"]`; + - `countries` - list of country codes, e.g. `["de", "lu", "lt"]`; + - `continents` - list of continent codes, e.g. + `["af", "an", "eu", "as", "na", "sa", "oc"]`. + + If there is a record (or multiple) with metadata matched IP, it's used as a + response. If not - asn, then country and then continent are checked for a match. + If there is no match, then the behaviour is defined by _strict_ parameter of the + filter. + + Example: `"pickers": [ { "type": "geodns", "strict": true } ]` + + Strict parameter `strict: true` means that if no records percolate through the + geodns filter it returns no answers. `strict: false` means that if no records + percolate through the geodns filter, all records are passed over. + + asn selector Resource records which ASN metadata matches ASN of the requestor + are picked by this selector, and passed to the next non-selector picker, if + there is no match - next configured picker starts with all records. + + Example: `"pickers": [ {"type": "asn"} ]` + + country selector Resource records which country metadata matches country of the + requestor are picked by this selector, and passed to the next non-selector + picker, if there is no match - next configured picker starts with all records. + + Example: `"pickers": [ { "type": "country" } ]` + + continent selector Resource records which continent metadata matches continent + of the requestor are picked by this selector, and passed to the next + non-selector picker, if there is no match - next configured picker starts with + all records. + + Example: `"pickers": [ { "type": "continent" } ]` + + region selector Resource records which region metadata matches region of the + requestor are picked by this selector, and passed to the next non-selector + picker, if there is no match - next configured picker starts with all records. + e.g. `fr-nor` for France/Normandy. + + Example: `"pickers": [ { "type": "region" } ]` + + ip selector Resource records which IP metadata matches IP of the requestor are + picked by this selector, and passed to the next non-selector picker, if there is + no match - next configured picker starts with all records. Maximum 100 subnets + are allowed to specify in meta of RR. + + Example: `"pickers": [ { "type": "ip" } ]` + + default selector When enabled, records marked as default are selected: + `"meta": {"default": true}`. + + Example: + `"pickers": [ { "type": "geodns", "strict": false }, { "type": "default" }, { "type": "first_n", "limit": 2 } ]` + + geodistance mutator The resource records are rearranged in ascending order based + on the distance (in meters) from requestor to the coordinates specified in + latlong metadata. Distance is calculated using Haversine formula. The "nearest" + to the user's IP RR goes first. The records without latlong metadata come last. + e.g. for Berlin `[52.520008, 13.404954]`.; + + In this configuration the only "nearest" to the requestor record to be returned: + `"pickers": [ { "type": "geodistance" }, { "type": "first_n", "limit": 1 } ]` + + `weighted_shuffle` mutator The resource records are rearranged in random order + based on the `weight` metadata. Default weight (if not specified) is 50. + + Example: `"pickers": [ { "type": "weighted_shuffle" } ]` + + `first_n` filter Slices first N (N specified as a limit parameter value) + resource records. + + Example: `"pickers": [ { "type": "first_n", "limit": 1 } ]` returns only the + first resource record. + + limit parameter Can be a positive value for a specific limit. Use zero or leave + it blank to indicate no limits. + + Args: + resource_records: List of resource record from rrset + + meta: Meta information for rrset + + pickers: Set of pickers + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + if not rrset_name: + raise ValueError(f"Expected a non-empty value for `rrset_name` but received {rrset_name!r}") + if not rrset_type: + raise ValueError(f"Expected a non-empty value for `rrset_type` but received {rrset_type!r}") + return self._post( + f"/dns/v2/zones/{zone_name}/{rrset_name}/{rrset_type}", + body=maybe_transform( + { + "resource_records": resource_records, + "meta": meta, + "pickers": pickers, + "ttl": ttl, + }, + rrset_create_params.RrsetCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DNSOutputRrset, + ) + + def list( + self, + zone_name: str, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: str | Omit = omit, + order_direction: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RrsetListResponse: + """ + List of RRset. + + Args: + limit: Max number of records in response + + offset: Amount of records to skip before beginning to write in response. + + order_by: Field name to sort by + + order_direction: Ascending or descending order + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + return self._get( + f"/dns/v2/zones/{zone_name}/rrsets", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + "order_by": order_by, + "order_direction": order_direction, + }, + rrset_list_params.RrsetListParams, + ), + ), + cast_to=RrsetListResponse, + ) + + def delete( + self, + rrset_type: str, + *, + zone_name: str, + rrset_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Delete RRset. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + if not rrset_name: + raise ValueError(f"Expected a non-empty value for `rrset_name` but received {rrset_name!r}") + if not rrset_type: + raise ValueError(f"Expected a non-empty value for `rrset_type` but received {rrset_type!r}") + return self._delete( + f"/dns/v2/zones/{zone_name}/{rrset_name}/{rrset_type}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def get( + self, + rrset_type: str, + *, + zone_name: str, + rrset_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSOutputRrset: + """ + Particular RRset item info + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + if not rrset_name: + raise ValueError(f"Expected a non-empty value for `rrset_name` but received {rrset_name!r}") + if not rrset_type: + raise ValueError(f"Expected a non-empty value for `rrset_type` but received {rrset_type!r}") + return self._get( + f"/dns/v2/zones/{zone_name}/{rrset_name}/{rrset_type}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DNSOutputRrset, + ) + + def get_failover_logs( + self, + rrset_type: str, + *, + zone_name: str, + rrset_name: str, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RrsetGetFailoverLogsResponse: + """ + Get failover history for the RRset + + Args: + limit: Max number of records in response + + offset: Amount of records to skip before beginning to write in response. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + if not rrset_name: + raise ValueError(f"Expected a non-empty value for `rrset_name` but received {rrset_name!r}") + if not rrset_type: + raise ValueError(f"Expected a non-empty value for `rrset_type` but received {rrset_type!r}") + return self._get( + f"/dns/v2/zones/{zone_name}/{rrset_name}/{rrset_type}/failover/log", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + rrset_get_failover_logs_params.RrsetGetFailoverLogsParams, + ), + ), + cast_to=RrsetGetFailoverLogsResponse, + ) + + def replace( + self, + rrset_type: str, + *, + zone_name: str, + rrset_name: str, + resource_records: Iterable[rrset_replace_params.ResourceRecord], + meta: Dict[str, object] | Omit = omit, + pickers: Iterable[rrset_replace_params.Picker] | Omit = omit, + ttl: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSOutputRrset: + """ + Create/update RRset. + + Args: + resource_records: List of resource record from rrset + + meta: Meta information for rrset + + pickers: Set of pickers + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + if not rrset_name: + raise ValueError(f"Expected a non-empty value for `rrset_name` but received {rrset_name!r}") + if not rrset_type: + raise ValueError(f"Expected a non-empty value for `rrset_type` but received {rrset_type!r}") + return self._put( + f"/dns/v2/zones/{zone_name}/{rrset_name}/{rrset_type}", + body=maybe_transform( + { + "resource_records": resource_records, + "meta": meta, + "pickers": pickers, + "ttl": ttl, + }, + rrset_replace_params.RrsetReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DNSOutputRrset, + ) + + +class AsyncRrsetsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRrsetsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncRrsetsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRrsetsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncRrsetsResourceWithStreamingResponse(self) + + async def create( + self, + rrset_type: str, + *, + zone_name: str, + rrset_name: str, + resource_records: Iterable[rrset_create_params.ResourceRecord], + meta: Dict[str, object] | Omit = omit, + pickers: Iterable[rrset_create_params.Picker] | Omit = omit, + ttl: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSOutputRrset: + """ + Add the RRSet to the zone specified by zoneName, RRSets can be configured to be + either dynamic or static. + + Static RRsets Staticly configured RRSets provide DNS responses as is. + + Dynamic RRsets Dynamic RRSets have picker configuration defined thus it's + possible to finely customize DNS response. Picking rules are defined on the + RRSet level as a list of selectors, filters and mutators. Picker considers + different resource records metadata, requestor IP, and other event-feeds like + monitoring. Picker configuration is an ordered list defined by "pickers" + attribute. Requestor IP is determined by EDNS Client Subnet (ECS) if defined, + otherwise - by client/recursor IP. Selector pickers are used in the specified + order until the first match, in case of match - all next selectors are bypassed. + Filters or mutators are applied to the match according to the order they are + specified. + + For example, sort records by proximity to user, shuffle based on weights and + return not more than 3: + + `"pickers": [ { "type": "geodistance" }, { "type": "weighted_shuffle" }, { "type": "first_n", "limit": 3 } ]` + + geodns filter A resource record is included in the answer if resource record's + metadata matches requestor info. For each resource record in RRSet, the + following metadata is considered (in the order specified): + + - `ip` - list of network addresses in CIDR format, e.g. + `["192.168.15.150/25", "2003:de:2016::/48"]`; + - `asn` - list of autonomous system numbers, e.g. `[1234, 5678]`; + - `regions` - list of region codes, e.g. `["de-bw", "de-by"]`; + - `countries` - list of country codes, e.g. `["de", "lu", "lt"]`; + - `continents` - list of continent codes, e.g. + `["af", "an", "eu", "as", "na", "sa", "oc"]`. + + If there is a record (or multiple) with metadata matched IP, it's used as a + response. If not - asn, then country and then continent are checked for a match. + If there is no match, then the behaviour is defined by _strict_ parameter of the + filter. + + Example: `"pickers": [ { "type": "geodns", "strict": true } ]` + + Strict parameter `strict: true` means that if no records percolate through the + geodns filter it returns no answers. `strict: false` means that if no records + percolate through the geodns filter, all records are passed over. + + asn selector Resource records which ASN metadata matches ASN of the requestor + are picked by this selector, and passed to the next non-selector picker, if + there is no match - next configured picker starts with all records. + + Example: `"pickers": [ {"type": "asn"} ]` + + country selector Resource records which country metadata matches country of the + requestor are picked by this selector, and passed to the next non-selector + picker, if there is no match - next configured picker starts with all records. + + Example: `"pickers": [ { "type": "country" } ]` + + continent selector Resource records which continent metadata matches continent + of the requestor are picked by this selector, and passed to the next + non-selector picker, if there is no match - next configured picker starts with + all records. + + Example: `"pickers": [ { "type": "continent" } ]` + + region selector Resource records which region metadata matches region of the + requestor are picked by this selector, and passed to the next non-selector + picker, if there is no match - next configured picker starts with all records. + e.g. `fr-nor` for France/Normandy. + + Example: `"pickers": [ { "type": "region" } ]` + + ip selector Resource records which IP metadata matches IP of the requestor are + picked by this selector, and passed to the next non-selector picker, if there is + no match - next configured picker starts with all records. Maximum 100 subnets + are allowed to specify in meta of RR. + + Example: `"pickers": [ { "type": "ip" } ]` + + default selector When enabled, records marked as default are selected: + `"meta": {"default": true}`. + + Example: + `"pickers": [ { "type": "geodns", "strict": false }, { "type": "default" }, { "type": "first_n", "limit": 2 } ]` + + geodistance mutator The resource records are rearranged in ascending order based + on the distance (in meters) from requestor to the coordinates specified in + latlong metadata. Distance is calculated using Haversine formula. The "nearest" + to the user's IP RR goes first. The records without latlong metadata come last. + e.g. for Berlin `[52.520008, 13.404954]`.; + + In this configuration the only "nearest" to the requestor record to be returned: + `"pickers": [ { "type": "geodistance" }, { "type": "first_n", "limit": 1 } ]` + + `weighted_shuffle` mutator The resource records are rearranged in random order + based on the `weight` metadata. Default weight (if not specified) is 50. + + Example: `"pickers": [ { "type": "weighted_shuffle" } ]` + + `first_n` filter Slices first N (N specified as a limit parameter value) + resource records. + + Example: `"pickers": [ { "type": "first_n", "limit": 1 } ]` returns only the + first resource record. + + limit parameter Can be a positive value for a specific limit. Use zero or leave + it blank to indicate no limits. + + Args: + resource_records: List of resource record from rrset + + meta: Meta information for rrset + + pickers: Set of pickers + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + if not rrset_name: + raise ValueError(f"Expected a non-empty value for `rrset_name` but received {rrset_name!r}") + if not rrset_type: + raise ValueError(f"Expected a non-empty value for `rrset_type` but received {rrset_type!r}") + return await self._post( + f"/dns/v2/zones/{zone_name}/{rrset_name}/{rrset_type}", + body=await async_maybe_transform( + { + "resource_records": resource_records, + "meta": meta, + "pickers": pickers, + "ttl": ttl, + }, + rrset_create_params.RrsetCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DNSOutputRrset, + ) + + async def list( + self, + zone_name: str, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: str | Omit = omit, + order_direction: Literal["asc", "desc"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RrsetListResponse: + """ + List of RRset. + + Args: + limit: Max number of records in response + + offset: Amount of records to skip before beginning to write in response. + + order_by: Field name to sort by + + order_direction: Ascending or descending order + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + return await self._get( + f"/dns/v2/zones/{zone_name}/rrsets", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "limit": limit, + "offset": offset, + "order_by": order_by, + "order_direction": order_direction, + }, + rrset_list_params.RrsetListParams, + ), + ), + cast_to=RrsetListResponse, + ) + + async def delete( + self, + rrset_type: str, + *, + zone_name: str, + rrset_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Delete RRset. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + if not rrset_name: + raise ValueError(f"Expected a non-empty value for `rrset_name` but received {rrset_name!r}") + if not rrset_type: + raise ValueError(f"Expected a non-empty value for `rrset_type` but received {rrset_type!r}") + return await self._delete( + f"/dns/v2/zones/{zone_name}/{rrset_name}/{rrset_type}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def get( + self, + rrset_type: str, + *, + zone_name: str, + rrset_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSOutputRrset: + """ + Particular RRset item info + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + if not rrset_name: + raise ValueError(f"Expected a non-empty value for `rrset_name` but received {rrset_name!r}") + if not rrset_type: + raise ValueError(f"Expected a non-empty value for `rrset_type` but received {rrset_type!r}") + return await self._get( + f"/dns/v2/zones/{zone_name}/{rrset_name}/{rrset_type}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DNSOutputRrset, + ) + + async def get_failover_logs( + self, + rrset_type: str, + *, + zone_name: str, + rrset_name: str, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RrsetGetFailoverLogsResponse: + """ + Get failover history for the RRset + + Args: + limit: Max number of records in response + + offset: Amount of records to skip before beginning to write in response. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + if not rrset_name: + raise ValueError(f"Expected a non-empty value for `rrset_name` but received {rrset_name!r}") + if not rrset_type: + raise ValueError(f"Expected a non-empty value for `rrset_type` but received {rrset_type!r}") + return await self._get( + f"/dns/v2/zones/{zone_name}/{rrset_name}/{rrset_type}/failover/log", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "limit": limit, + "offset": offset, + }, + rrset_get_failover_logs_params.RrsetGetFailoverLogsParams, + ), + ), + cast_to=RrsetGetFailoverLogsResponse, + ) + + async def replace( + self, + rrset_type: str, + *, + zone_name: str, + rrset_name: str, + resource_records: Iterable[rrset_replace_params.ResourceRecord], + meta: Dict[str, object] | Omit = omit, + pickers: Iterable[rrset_replace_params.Picker] | Omit = omit, + ttl: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DNSOutputRrset: + """ + Create/update RRset. + + Args: + resource_records: List of resource record from rrset + + meta: Meta information for rrset + + pickers: Set of pickers + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + if not rrset_name: + raise ValueError(f"Expected a non-empty value for `rrset_name` but received {rrset_name!r}") + if not rrset_type: + raise ValueError(f"Expected a non-empty value for `rrset_type` but received {rrset_type!r}") + return await self._put( + f"/dns/v2/zones/{zone_name}/{rrset_name}/{rrset_type}", + body=await async_maybe_transform( + { + "resource_records": resource_records, + "meta": meta, + "pickers": pickers, + "ttl": ttl, + }, + rrset_replace_params.RrsetReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DNSOutputRrset, + ) + + +class RrsetsResourceWithRawResponse: + def __init__(self, rrsets: RrsetsResource) -> None: + self._rrsets = rrsets + + self.create = to_raw_response_wrapper( + rrsets.create, + ) + self.list = to_raw_response_wrapper( + rrsets.list, + ) + self.delete = to_raw_response_wrapper( + rrsets.delete, + ) + self.get = to_raw_response_wrapper( + rrsets.get, + ) + self.get_failover_logs = to_raw_response_wrapper( + rrsets.get_failover_logs, + ) + self.replace = to_raw_response_wrapper( + rrsets.replace, + ) + + +class AsyncRrsetsResourceWithRawResponse: + def __init__(self, rrsets: AsyncRrsetsResource) -> None: + self._rrsets = rrsets + + self.create = async_to_raw_response_wrapper( + rrsets.create, + ) + self.list = async_to_raw_response_wrapper( + rrsets.list, + ) + self.delete = async_to_raw_response_wrapper( + rrsets.delete, + ) + self.get = async_to_raw_response_wrapper( + rrsets.get, + ) + self.get_failover_logs = async_to_raw_response_wrapper( + rrsets.get_failover_logs, + ) + self.replace = async_to_raw_response_wrapper( + rrsets.replace, + ) + + +class RrsetsResourceWithStreamingResponse: + def __init__(self, rrsets: RrsetsResource) -> None: + self._rrsets = rrsets + + self.create = to_streamed_response_wrapper( + rrsets.create, + ) + self.list = to_streamed_response_wrapper( + rrsets.list, + ) + self.delete = to_streamed_response_wrapper( + rrsets.delete, + ) + self.get = to_streamed_response_wrapper( + rrsets.get, + ) + self.get_failover_logs = to_streamed_response_wrapper( + rrsets.get_failover_logs, + ) + self.replace = to_streamed_response_wrapper( + rrsets.replace, + ) + + +class AsyncRrsetsResourceWithStreamingResponse: + def __init__(self, rrsets: AsyncRrsetsResource) -> None: + self._rrsets = rrsets + + self.create = async_to_streamed_response_wrapper( + rrsets.create, + ) + self.list = async_to_streamed_response_wrapper( + rrsets.list, + ) + self.delete = async_to_streamed_response_wrapper( + rrsets.delete, + ) + self.get = async_to_streamed_response_wrapper( + rrsets.get, + ) + self.get_failover_logs = async_to_streamed_response_wrapper( + rrsets.get_failover_logs, + ) + self.replace = async_to_streamed_response_wrapper( + rrsets.replace, + ) diff --git a/src/gcore/resources/dns/zones/zones.py b/src/gcore/resources/dns/zones/zones.py new file mode 100644 index 00000000..94bf34c2 --- /dev/null +++ b/src/gcore/resources/dns/zones/zones.py @@ -0,0 +1,1515 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from .dnssec import ( + DnssecResource, + AsyncDnssecResource, + DnssecResourceWithRawResponse, + AsyncDnssecResourceWithRawResponse, + DnssecResourceWithStreamingResponse, + AsyncDnssecResourceWithStreamingResponse, +) +from .rrsets import ( + RrsetsResource, + AsyncRrsetsResource, + RrsetsResourceWithRawResponse, + AsyncRrsetsResourceWithRawResponse, + RrsetsResourceWithStreamingResponse, + AsyncRrsetsResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....types.dns import ( + zone_list_params, + zone_create_params, + zone_import_params, + zone_replace_params, + zone_get_statistics_params, +) +from ...._base_client import make_request_options +from ....types.dns.zone_get_response import ZoneGetResponse +from ....types.dns.zone_list_response import ZoneListResponse +from ....types.dns.zone_create_response import ZoneCreateResponse +from ....types.dns.zone_export_response import ZoneExportResponse +from ....types.dns.zone_import_response import ZoneImportResponse +from ....types.dns.zone_get_statistics_response import ZoneGetStatisticsResponse +from ....types.dns.zone_check_delegation_status_response import ZoneCheckDelegationStatusResponse + +__all__ = ["ZonesResource", "AsyncZonesResource"] + + +class ZonesResource(SyncAPIResource): + @cached_property + def dnssec(self) -> DnssecResource: + return DnssecResource(self._client) + + @cached_property + def rrsets(self) -> RrsetsResource: + return RrsetsResource(self._client) + + @cached_property + def with_raw_response(self) -> ZonesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ZonesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ZonesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ZonesResourceWithStreamingResponse(self) + + def create( + self, + *, + name: str, + contact: str | Omit = omit, + enabled: bool | Omit = omit, + expiry: int | Omit = omit, + meta: Dict[str, object] | Omit = omit, + nx_ttl: int | Omit = omit, + primary_server: str | Omit = omit, + refresh: int | Omit = omit, + retry: int | Omit = omit, + serial: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneCreateResponse: + """ + Add DNS zone. + + Args: + name: name of DNS zone + + contact: email address of the administrator responsible for this zone + + enabled: If a zone is disabled, then its records will not be resolved on dns servers + + expiry: number of seconds after which secondary name servers should stop answering + request for this zone + + meta: arbitrarily data of zone in json format you can specify `webhook` url and + `webhook_method` here webhook will get a map with three arrays: for created, + updated and deleted rrsets `webhook_method` can be omitted, POST will be used by + default + + nx_ttl: Time To Live of cache + + primary_server: primary master name server for zone + + refresh: number of seconds after which secondary name servers should query the master for + the SOA record, to detect zone changes. + + retry: number of seconds after which secondary name servers should retry to request the + serial number + + serial: Serial number for this zone or Timestamp of zone modification moment. If a + secondary name server slaved to this one observes an increase in this number, + the slave will assume that the zone has been updated and initiate a zone + transfer. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/dns/v2/zones", + body=maybe_transform( + { + "name": name, + "contact": contact, + "enabled": enabled, + "expiry": expiry, + "meta": meta, + "nx_ttl": nx_ttl, + "primary_server": primary_server, + "refresh": refresh, + "retry": retry, + "serial": serial, + }, + zone_create_params.ZoneCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ZoneCreateResponse, + ) + + def list( + self, + *, + id: Iterable[int] | Omit = omit, + case_sensitive: bool | Omit = omit, + client_id: Iterable[int] | Omit = omit, + dynamic: bool | Omit = omit, + enabled: bool | Omit = omit, + exact_match: bool | Omit = omit, + healthcheck: bool | Omit = omit, + iam_reseller_id: Iterable[int] | Omit = omit, + limit: int | Omit = omit, + name: SequenceNotStr[str] | Omit = omit, + offset: int | Omit = omit, + order_by: str | Omit = omit, + order_direction: Literal["asc", "desc"] | Omit = omit, + reseller_id: Iterable[int] | Omit = omit, + status: str | Omit = omit, + updated_at_from: Union[str, datetime] | Omit = omit, + updated_at_to: Union[str, datetime] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneListResponse: + """Show created zones with pagination managed by limit and offset params. + + All query + params are optional. + + Args: + id: to pass several ids `id=1&id=3&id=5...` + + client_id: to pass several `client_ids` `client_id=1&client_id=3&client_id=5...` + + dynamic: Zones with dynamic RRsets + + healthcheck: Zones with RRsets that have healthchecks + + limit: Max number of records in response + + name: to pass several names `name=first&name=second...` + + offset: Amount of records to skip before beginning to write in response. + + order_by: Field name to sort by + + order_direction: Ascending or descending order + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/dns/v2/zones", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "id": id, + "case_sensitive": case_sensitive, + "client_id": client_id, + "dynamic": dynamic, + "enabled": enabled, + "exact_match": exact_match, + "healthcheck": healthcheck, + "iam_reseller_id": iam_reseller_id, + "limit": limit, + "name": name, + "offset": offset, + "order_by": order_by, + "order_direction": order_direction, + "reseller_id": reseller_id, + "status": status, + "updated_at_from": updated_at_from, + "updated_at_to": updated_at_to, + }, + zone_list_params.ZoneListParams, + ), + ), + cast_to=ZoneListResponse, + ) + + def delete( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Delete DNS zone and its records and raws. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return self._delete( + f"/dns/v2/zones/{name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def check_delegation_status( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneCheckDelegationStatusResponse: + """Returns delegation status for specified domain name. + + This endpoint has rate + limit. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return self._get( + f"/dns/v2/analyze/{name}/delegation-status", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ZoneCheckDelegationStatusResponse, + ) + + def disable( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Disable DNS zone. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return self._patch( + f"/dns/v2/zones/{name}/disable", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def enable( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Enable DNS zone. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return self._patch( + f"/dns/v2/zones/{name}/enable", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def export( + self, + zone_name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneExportResponse: + """ + Export zone to bind9 format. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + return self._get( + f"/dns/v2/zones/{zone_name}/export", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ZoneExportResponse, + ) + + def get( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneGetResponse: + """ + Zone info by zone name. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return self._get( + f"/dns/v2/zones/{name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ZoneGetResponse, + ) + + def get_statistics( + self, + name: str, + *, + from_: int | Omit = omit, + granularity: str | Omit = omit, + record_type: str | Omit = omit, + to: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneGetStatisticsResponse: + """ + Statistics of DNS zone in common and by record types. + + To get summary statistics for all zones use `all` instead of zone name in path. + + Note: Consumption statistics is updated in near real-time as a standard + practice. However, the frequency of updates can vary, but they are typically + available within a 30 minutes period. Exceptions, such as maintenance periods, + may delay data beyond 30 minutes until servers resume and backfill missing + statistics. + + Args: + from_: Beginning of the requested time period (Unix Timestamp, UTC.) + + In a query string: &from=1709068637 + + granularity: Granularity parameter string is a sequence of decimal numbers, each with + optional fraction and a unit suffix, such as "300ms", "1.5h" or "2h45m". + + Valid time units are "s", "m", "h". + + record_type: DNS record type. + + Possible values: + + - A + - AAAA + - NS + - CNAME + - MX + - TXT + - SVCB + - HTTPS + + to: End of the requested time period (Unix Timestamp, UTC.) + + In a query string: &to=1709673437 + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return self._get( + f"/dns/v2/zones/{name}/statistics", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "granularity": granularity, + "record_type": record_type, + "to": to, + }, + zone_get_statistics_params.ZoneGetStatisticsParams, + ), + ), + cast_to=ZoneGetStatisticsResponse, + ) + + def import_( + self, + zone_name: str, + *, + body: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneImportResponse: + """Import zone in bind9 format. + + Args: + body: Read reads up to len(p) bytes into p. + + It returns the number of bytes read (0 <= + n <= len(p)) and any error encountered. Even if Read returns n < len(p), it may + use all of p as scratch space during the call. If some data is available but not + len(p) bytes, Read conventionally returns what is available instead of waiting + for more. + + When Read encounters an error or end-of-file condition after successfully + reading n > 0 bytes, it returns the number of bytes read. It may return the + (non-nil) error from the same call or return the error (and n == 0) from a + subsequent call. An instance of this general case is that a Reader returning a + non-zero number of bytes at the end of the input stream may return either err == + EOF or err == nil. The next Read should return 0, EOF. + + Callers should always process the n > 0 bytes returned before considering the + error err. Doing so correctly handles I/O errors that happen after reading some + bytes and also both of the allowed EOF behaviors. + + If len(p) == 0, Read should always return n == 0. It may return a non-nil error + if some error condition is known, such as EOF. + + Implementations of Read are discouraged from returning a zero byte count with a + nil error, except when len(p) == 0. Callers should treat a return of 0 and nil + as indicating that nothing happened; in particular it does not indicate EOF. + + Implementations must not retain p. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + return self._post( + f"/dns/v2/zones/{zone_name}/import", + body=maybe_transform(body, zone_import_params.ZoneImportParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ZoneImportResponse, + ) + + def replace( + self, + path_name: str, + *, + body_name: str, + contact: str | Omit = omit, + enabled: bool | Omit = omit, + expiry: int | Omit = omit, + meta: Dict[str, object] | Omit = omit, + nx_ttl: int | Omit = omit, + primary_server: str | Omit = omit, + refresh: int | Omit = omit, + retry: int | Omit = omit, + serial: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Update DNS zone and SOA record. + + Args: + body_name: name of DNS zone + + contact: email address of the administrator responsible for this zone + + enabled: If a zone is disabled, then its records will not be resolved on dns servers + + expiry: number of seconds after which secondary name servers should stop answering + request for this zone + + meta: arbitrarily data of zone in json format you can specify `webhook` url and + `webhook_method` here webhook will get a map with three arrays: for created, + updated and deleted rrsets `webhook_method` can be omitted, POST will be used by + default + + nx_ttl: Time To Live of cache + + primary_server: primary master name server for zone + + refresh: number of seconds after which secondary name servers should query the master for + the SOA record, to detect zone changes. + + retry: number of seconds after which secondary name servers should retry to request the + serial number + + serial: Serial number for this zone or Timestamp of zone modification moment. If a + secondary name server slaved to this one observes an increase in this number, + the slave will assume that the zone has been updated and initiate a zone + transfer. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not path_name: + raise ValueError(f"Expected a non-empty value for `path_name` but received {path_name!r}") + return self._put( + f"/dns/v2/zones/{path_name}", + body=maybe_transform( + { + "body_name": body_name, + "contact": contact, + "enabled": enabled, + "expiry": expiry, + "meta": meta, + "nx_ttl": nx_ttl, + "primary_server": primary_server, + "refresh": refresh, + "retry": retry, + "serial": serial, + }, + zone_replace_params.ZoneReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class AsyncZonesResource(AsyncAPIResource): + @cached_property + def dnssec(self) -> AsyncDnssecResource: + return AsyncDnssecResource(self._client) + + @cached_property + def rrsets(self) -> AsyncRrsetsResource: + return AsyncRrsetsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncZonesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncZonesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncZonesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncZonesResourceWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + contact: str | Omit = omit, + enabled: bool | Omit = omit, + expiry: int | Omit = omit, + meta: Dict[str, object] | Omit = omit, + nx_ttl: int | Omit = omit, + primary_server: str | Omit = omit, + refresh: int | Omit = omit, + retry: int | Omit = omit, + serial: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneCreateResponse: + """ + Add DNS zone. + + Args: + name: name of DNS zone + + contact: email address of the administrator responsible for this zone + + enabled: If a zone is disabled, then its records will not be resolved on dns servers + + expiry: number of seconds after which secondary name servers should stop answering + request for this zone + + meta: arbitrarily data of zone in json format you can specify `webhook` url and + `webhook_method` here webhook will get a map with three arrays: for created, + updated and deleted rrsets `webhook_method` can be omitted, POST will be used by + default + + nx_ttl: Time To Live of cache + + primary_server: primary master name server for zone + + refresh: number of seconds after which secondary name servers should query the master for + the SOA record, to detect zone changes. + + retry: number of seconds after which secondary name servers should retry to request the + serial number + + serial: Serial number for this zone or Timestamp of zone modification moment. If a + secondary name server slaved to this one observes an increase in this number, + the slave will assume that the zone has been updated and initiate a zone + transfer. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/dns/v2/zones", + body=await async_maybe_transform( + { + "name": name, + "contact": contact, + "enabled": enabled, + "expiry": expiry, + "meta": meta, + "nx_ttl": nx_ttl, + "primary_server": primary_server, + "refresh": refresh, + "retry": retry, + "serial": serial, + }, + zone_create_params.ZoneCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ZoneCreateResponse, + ) + + async def list( + self, + *, + id: Iterable[int] | Omit = omit, + case_sensitive: bool | Omit = omit, + client_id: Iterable[int] | Omit = omit, + dynamic: bool | Omit = omit, + enabled: bool | Omit = omit, + exact_match: bool | Omit = omit, + healthcheck: bool | Omit = omit, + iam_reseller_id: Iterable[int] | Omit = omit, + limit: int | Omit = omit, + name: SequenceNotStr[str] | Omit = omit, + offset: int | Omit = omit, + order_by: str | Omit = omit, + order_direction: Literal["asc", "desc"] | Omit = omit, + reseller_id: Iterable[int] | Omit = omit, + status: str | Omit = omit, + updated_at_from: Union[str, datetime] | Omit = omit, + updated_at_to: Union[str, datetime] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneListResponse: + """Show created zones with pagination managed by limit and offset params. + + All query + params are optional. + + Args: + id: to pass several ids `id=1&id=3&id=5...` + + client_id: to pass several `client_ids` `client_id=1&client_id=3&client_id=5...` + + dynamic: Zones with dynamic RRsets + + healthcheck: Zones with RRsets that have healthchecks + + limit: Max number of records in response + + name: to pass several names `name=first&name=second...` + + offset: Amount of records to skip before beginning to write in response. + + order_by: Field name to sort by + + order_direction: Ascending or descending order + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/dns/v2/zones", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "id": id, + "case_sensitive": case_sensitive, + "client_id": client_id, + "dynamic": dynamic, + "enabled": enabled, + "exact_match": exact_match, + "healthcheck": healthcheck, + "iam_reseller_id": iam_reseller_id, + "limit": limit, + "name": name, + "offset": offset, + "order_by": order_by, + "order_direction": order_direction, + "reseller_id": reseller_id, + "status": status, + "updated_at_from": updated_at_from, + "updated_at_to": updated_at_to, + }, + zone_list_params.ZoneListParams, + ), + ), + cast_to=ZoneListResponse, + ) + + async def delete( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Delete DNS zone and its records and raws. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return await self._delete( + f"/dns/v2/zones/{name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def check_delegation_status( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneCheckDelegationStatusResponse: + """Returns delegation status for specified domain name. + + This endpoint has rate + limit. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return await self._get( + f"/dns/v2/analyze/{name}/delegation-status", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ZoneCheckDelegationStatusResponse, + ) + + async def disable( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Disable DNS zone. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return await self._patch( + f"/dns/v2/zones/{name}/disable", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def enable( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Enable DNS zone. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return await self._patch( + f"/dns/v2/zones/{name}/enable", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def export( + self, + zone_name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneExportResponse: + """ + Export zone to bind9 format. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + return await self._get( + f"/dns/v2/zones/{zone_name}/export", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ZoneExportResponse, + ) + + async def get( + self, + name: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneGetResponse: + """ + Zone info by zone name. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return await self._get( + f"/dns/v2/zones/{name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ZoneGetResponse, + ) + + async def get_statistics( + self, + name: str, + *, + from_: int | Omit = omit, + granularity: str | Omit = omit, + record_type: str | Omit = omit, + to: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneGetStatisticsResponse: + """ + Statistics of DNS zone in common and by record types. + + To get summary statistics for all zones use `all` instead of zone name in path. + + Note: Consumption statistics is updated in near real-time as a standard + practice. However, the frequency of updates can vary, but they are typically + available within a 30 minutes period. Exceptions, such as maintenance periods, + may delay data beyond 30 minutes until servers resume and backfill missing + statistics. + + Args: + from_: Beginning of the requested time period (Unix Timestamp, UTC.) + + In a query string: &from=1709068637 + + granularity: Granularity parameter string is a sequence of decimal numbers, each with + optional fraction and a unit suffix, such as "300ms", "1.5h" or "2h45m". + + Valid time units are "s", "m", "h". + + record_type: DNS record type. + + Possible values: + + - A + - AAAA + - NS + - CNAME + - MX + - TXT + - SVCB + - HTTPS + + to: End of the requested time period (Unix Timestamp, UTC.) + + In a query string: &to=1709673437 + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") + return await self._get( + f"/dns/v2/zones/{name}/statistics", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "granularity": granularity, + "record_type": record_type, + "to": to, + }, + zone_get_statistics_params.ZoneGetStatisticsParams, + ), + ), + cast_to=ZoneGetStatisticsResponse, + ) + + async def import_( + self, + zone_name: str, + *, + body: object | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ZoneImportResponse: + """Import zone in bind9 format. + + Args: + body: Read reads up to len(p) bytes into p. + + It returns the number of bytes read (0 <= + n <= len(p)) and any error encountered. Even if Read returns n < len(p), it may + use all of p as scratch space during the call. If some data is available but not + len(p) bytes, Read conventionally returns what is available instead of waiting + for more. + + When Read encounters an error or end-of-file condition after successfully + reading n > 0 bytes, it returns the number of bytes read. It may return the + (non-nil) error from the same call or return the error (and n == 0) from a + subsequent call. An instance of this general case is that a Reader returning a + non-zero number of bytes at the end of the input stream may return either err == + EOF or err == nil. The next Read should return 0, EOF. + + Callers should always process the n > 0 bytes returned before considering the + error err. Doing so correctly handles I/O errors that happen after reading some + bytes and also both of the allowed EOF behaviors. + + If len(p) == 0, Read should always return n == 0. It may return a non-nil error + if some error condition is known, such as EOF. + + Implementations of Read are discouraged from returning a zero byte count with a + nil error, except when len(p) == 0. Callers should treat a return of 0 and nil + as indicating that nothing happened; in particular it does not indicate EOF. + + Implementations must not retain p. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not zone_name: + raise ValueError(f"Expected a non-empty value for `zone_name` but received {zone_name!r}") + return await self._post( + f"/dns/v2/zones/{zone_name}/import", + body=await async_maybe_transform(body, zone_import_params.ZoneImportParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ZoneImportResponse, + ) + + async def replace( + self, + path_name: str, + *, + body_name: str, + contact: str | Omit = omit, + enabled: bool | Omit = omit, + expiry: int | Omit = omit, + meta: Dict[str, object] | Omit = omit, + nx_ttl: int | Omit = omit, + primary_server: str | Omit = omit, + refresh: int | Omit = omit, + retry: int | Omit = omit, + serial: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """ + Update DNS zone and SOA record. + + Args: + body_name: name of DNS zone + + contact: email address of the administrator responsible for this zone + + enabled: If a zone is disabled, then its records will not be resolved on dns servers + + expiry: number of seconds after which secondary name servers should stop answering + request for this zone + + meta: arbitrarily data of zone in json format you can specify `webhook` url and + `webhook_method` here webhook will get a map with three arrays: for created, + updated and deleted rrsets `webhook_method` can be omitted, POST will be used by + default + + nx_ttl: Time To Live of cache + + primary_server: primary master name server for zone + + refresh: number of seconds after which secondary name servers should query the master for + the SOA record, to detect zone changes. + + retry: number of seconds after which secondary name servers should retry to request the + serial number + + serial: Serial number for this zone or Timestamp of zone modification moment. If a + secondary name server slaved to this one observes an increase in this number, + the slave will assume that the zone has been updated and initiate a zone + transfer. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not path_name: + raise ValueError(f"Expected a non-empty value for `path_name` but received {path_name!r}") + return await self._put( + f"/dns/v2/zones/{path_name}", + body=await async_maybe_transform( + { + "body_name": body_name, + "contact": contact, + "enabled": enabled, + "expiry": expiry, + "meta": meta, + "nx_ttl": nx_ttl, + "primary_server": primary_server, + "refresh": refresh, + "retry": retry, + "serial": serial, + }, + zone_replace_params.ZoneReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + +class ZonesResourceWithRawResponse: + def __init__(self, zones: ZonesResource) -> None: + self._zones = zones + + self.create = to_raw_response_wrapper( + zones.create, + ) + self.list = to_raw_response_wrapper( + zones.list, + ) + self.delete = to_raw_response_wrapper( + zones.delete, + ) + self.check_delegation_status = to_raw_response_wrapper( + zones.check_delegation_status, + ) + self.disable = to_raw_response_wrapper( + zones.disable, + ) + self.enable = to_raw_response_wrapper( + zones.enable, + ) + self.export = to_raw_response_wrapper( + zones.export, + ) + self.get = to_raw_response_wrapper( + zones.get, + ) + self.get_statistics = to_raw_response_wrapper( + zones.get_statistics, + ) + self.import_ = to_raw_response_wrapper( + zones.import_, + ) + self.replace = to_raw_response_wrapper( + zones.replace, + ) + + @cached_property + def dnssec(self) -> DnssecResourceWithRawResponse: + return DnssecResourceWithRawResponse(self._zones.dnssec) + + @cached_property + def rrsets(self) -> RrsetsResourceWithRawResponse: + return RrsetsResourceWithRawResponse(self._zones.rrsets) + + +class AsyncZonesResourceWithRawResponse: + def __init__(self, zones: AsyncZonesResource) -> None: + self._zones = zones + + self.create = async_to_raw_response_wrapper( + zones.create, + ) + self.list = async_to_raw_response_wrapper( + zones.list, + ) + self.delete = async_to_raw_response_wrapper( + zones.delete, + ) + self.check_delegation_status = async_to_raw_response_wrapper( + zones.check_delegation_status, + ) + self.disable = async_to_raw_response_wrapper( + zones.disable, + ) + self.enable = async_to_raw_response_wrapper( + zones.enable, + ) + self.export = async_to_raw_response_wrapper( + zones.export, + ) + self.get = async_to_raw_response_wrapper( + zones.get, + ) + self.get_statistics = async_to_raw_response_wrapper( + zones.get_statistics, + ) + self.import_ = async_to_raw_response_wrapper( + zones.import_, + ) + self.replace = async_to_raw_response_wrapper( + zones.replace, + ) + + @cached_property + def dnssec(self) -> AsyncDnssecResourceWithRawResponse: + return AsyncDnssecResourceWithRawResponse(self._zones.dnssec) + + @cached_property + def rrsets(self) -> AsyncRrsetsResourceWithRawResponse: + return AsyncRrsetsResourceWithRawResponse(self._zones.rrsets) + + +class ZonesResourceWithStreamingResponse: + def __init__(self, zones: ZonesResource) -> None: + self._zones = zones + + self.create = to_streamed_response_wrapper( + zones.create, + ) + self.list = to_streamed_response_wrapper( + zones.list, + ) + self.delete = to_streamed_response_wrapper( + zones.delete, + ) + self.check_delegation_status = to_streamed_response_wrapper( + zones.check_delegation_status, + ) + self.disable = to_streamed_response_wrapper( + zones.disable, + ) + self.enable = to_streamed_response_wrapper( + zones.enable, + ) + self.export = to_streamed_response_wrapper( + zones.export, + ) + self.get = to_streamed_response_wrapper( + zones.get, + ) + self.get_statistics = to_streamed_response_wrapper( + zones.get_statistics, + ) + self.import_ = to_streamed_response_wrapper( + zones.import_, + ) + self.replace = to_streamed_response_wrapper( + zones.replace, + ) + + @cached_property + def dnssec(self) -> DnssecResourceWithStreamingResponse: + return DnssecResourceWithStreamingResponse(self._zones.dnssec) + + @cached_property + def rrsets(self) -> RrsetsResourceWithStreamingResponse: + return RrsetsResourceWithStreamingResponse(self._zones.rrsets) + + +class AsyncZonesResourceWithStreamingResponse: + def __init__(self, zones: AsyncZonesResource) -> None: + self._zones = zones + + self.create = async_to_streamed_response_wrapper( + zones.create, + ) + self.list = async_to_streamed_response_wrapper( + zones.list, + ) + self.delete = async_to_streamed_response_wrapper( + zones.delete, + ) + self.check_delegation_status = async_to_streamed_response_wrapper( + zones.check_delegation_status, + ) + self.disable = async_to_streamed_response_wrapper( + zones.disable, + ) + self.enable = async_to_streamed_response_wrapper( + zones.enable, + ) + self.export = async_to_streamed_response_wrapper( + zones.export, + ) + self.get = async_to_streamed_response_wrapper( + zones.get, + ) + self.get_statistics = async_to_streamed_response_wrapper( + zones.get_statistics, + ) + self.import_ = async_to_streamed_response_wrapper( + zones.import_, + ) + self.replace = async_to_streamed_response_wrapper( + zones.replace, + ) + + @cached_property + def dnssec(self) -> AsyncDnssecResourceWithStreamingResponse: + return AsyncDnssecResourceWithStreamingResponse(self._zones.dnssec) + + @cached_property + def rrsets(self) -> AsyncRrsetsResourceWithStreamingResponse: + return AsyncRrsetsResourceWithStreamingResponse(self._zones.rrsets) diff --git a/src/gcore/resources/fastedge/__init__.py b/src/gcore/resources/fastedge/__init__.py new file mode 100644 index 00000000..b2597842 --- /dev/null +++ b/src/gcore/resources/fastedge/__init__.py @@ -0,0 +1,103 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .apps import ( + AppsResource, + AsyncAppsResource, + AppsResourceWithRawResponse, + AsyncAppsResourceWithRawResponse, + AppsResourceWithStreamingResponse, + AsyncAppsResourceWithStreamingResponse, +) +from .secrets import ( + SecretsResource, + AsyncSecretsResource, + SecretsResourceWithRawResponse, + AsyncSecretsResourceWithRawResponse, + SecretsResourceWithStreamingResponse, + AsyncSecretsResourceWithStreamingResponse, +) +from .binaries import ( + BinariesResource, + AsyncBinariesResource, + BinariesResourceWithRawResponse, + AsyncBinariesResourceWithRawResponse, + BinariesResourceWithStreamingResponse, + AsyncBinariesResourceWithStreamingResponse, +) +from .fastedge import ( + FastedgeResource, + AsyncFastedgeResource, + FastedgeResourceWithRawResponse, + AsyncFastedgeResourceWithRawResponse, + FastedgeResourceWithStreamingResponse, + AsyncFastedgeResourceWithStreamingResponse, +) +from .kv_stores import ( + KvStoresResource, + AsyncKvStoresResource, + KvStoresResourceWithRawResponse, + AsyncKvStoresResourceWithRawResponse, + KvStoresResourceWithStreamingResponse, + AsyncKvStoresResourceWithStreamingResponse, +) +from .templates import ( + TemplatesResource, + AsyncTemplatesResource, + TemplatesResourceWithRawResponse, + AsyncTemplatesResourceWithRawResponse, + TemplatesResourceWithStreamingResponse, + AsyncTemplatesResourceWithStreamingResponse, +) +from .statistics import ( + StatisticsResource, + AsyncStatisticsResource, + StatisticsResourceWithRawResponse, + AsyncStatisticsResourceWithRawResponse, + StatisticsResourceWithStreamingResponse, + AsyncStatisticsResourceWithStreamingResponse, +) + +__all__ = [ + "TemplatesResource", + "AsyncTemplatesResource", + "TemplatesResourceWithRawResponse", + "AsyncTemplatesResourceWithRawResponse", + "TemplatesResourceWithStreamingResponse", + "AsyncTemplatesResourceWithStreamingResponse", + "SecretsResource", + "AsyncSecretsResource", + "SecretsResourceWithRawResponse", + "AsyncSecretsResourceWithRawResponse", + "SecretsResourceWithStreamingResponse", + "AsyncSecretsResourceWithStreamingResponse", + "BinariesResource", + "AsyncBinariesResource", + "BinariesResourceWithRawResponse", + "AsyncBinariesResourceWithRawResponse", + "BinariesResourceWithStreamingResponse", + "AsyncBinariesResourceWithStreamingResponse", + "StatisticsResource", + "AsyncStatisticsResource", + "StatisticsResourceWithRawResponse", + "AsyncStatisticsResourceWithRawResponse", + "StatisticsResourceWithStreamingResponse", + "AsyncStatisticsResourceWithStreamingResponse", + "AppsResource", + "AsyncAppsResource", + "AppsResourceWithRawResponse", + "AsyncAppsResourceWithRawResponse", + "AppsResourceWithStreamingResponse", + "AsyncAppsResourceWithStreamingResponse", + "KvStoresResource", + "AsyncKvStoresResource", + "KvStoresResourceWithRawResponse", + "AsyncKvStoresResourceWithRawResponse", + "KvStoresResourceWithStreamingResponse", + "AsyncKvStoresResourceWithStreamingResponse", + "FastedgeResource", + "AsyncFastedgeResource", + "FastedgeResourceWithRawResponse", + "AsyncFastedgeResourceWithRawResponse", + "FastedgeResourceWithStreamingResponse", + "AsyncFastedgeResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/fastedge/api.md b/src/gcore/resources/fastedge/api.md new file mode 100644 index 00000000..8d835d33 --- /dev/null +++ b/src/gcore/resources/fastedge/api.md @@ -0,0 +1,122 @@ +# Fastedge + +Types: + +```python +from gcore.types.fastedge import Client +``` + +Methods: + +- client.fastedge.get_account_overview() -> Client + +## Templates + +Types: + +```python +from gcore.types.fastedge import Template, TemplateParameter, TemplateShort +``` + +Methods: + +- client.fastedge.templates.create(\*\*params) -> TemplateShort +- client.fastedge.templates.list(\*\*params) -> SyncOffsetPageFastedgeTemplates[TemplateShort] +- client.fastedge.templates.delete(id, \*\*params) -> None +- client.fastedge.templates.get(id) -> Template +- client.fastedge.templates.replace(id, \*\*params) -> TemplateShort + +## Secrets + +Types: + +```python +from gcore.types.fastedge import Secret, SecretShort, SecretCreateResponse, SecretListResponse +``` + +Methods: + +- client.fastedge.secrets.create(\*\*params) -> SecretCreateResponse +- client.fastedge.secrets.update(id, \*\*params) -> Secret +- client.fastedge.secrets.list(\*\*params) -> SecretListResponse +- client.fastedge.secrets.delete(id, \*\*params) -> None +- client.fastedge.secrets.get(id) -> Secret +- client.fastedge.secrets.replace(id, \*\*params) -> Secret + +## Binaries + +Types: + +```python +from gcore.types.fastedge import Binary, BinaryShort, BinaryListResponse +``` + +Methods: + +- client.fastedge.binaries.create(body, \*\*params) -> BinaryShort +- client.fastedge.binaries.list() -> BinaryListResponse +- client.fastedge.binaries.delete(id) -> None +- client.fastedge.binaries.get(id) -> Binary + +## Statistics + +Types: + +```python +from gcore.types.fastedge import ( + CallStatus, + DurationStats, + StatisticGetCallSeriesResponse, + StatisticGetDurationSeriesResponse, +) +``` + +Methods: + +- client.fastedge.statistics.get_call_series(\*\*params) -> StatisticGetCallSeriesResponse +- client.fastedge.statistics.get_duration_series(\*\*params) -> StatisticGetDurationSeriesResponse + +## Apps + +Types: + +```python +from gcore.types.fastedge import App, AppShort +``` + +Methods: + +- client.fastedge.apps.create(\*\*params) -> AppShort +- client.fastedge.apps.update(id, \*\*params) -> AppShort +- client.fastedge.apps.list(\*\*params) -> SyncOffsetPageFastedgeApps[AppShort] +- client.fastedge.apps.delete(id) -> None +- client.fastedge.apps.get(id) -> App +- client.fastedge.apps.replace(id, \*\*params) -> AppShort + +### Logs + +Types: + +```python +from gcore.types.fastedge.apps import Log +``` + +Methods: + +- client.fastedge.apps.logs.list(id, \*\*params) -> SyncOffsetPageFastedgeAppLogs[Log] + +## KvStores + +Types: + +```python +from gcore.types.fastedge import KvStore, KvStoreShort, KvStoreCreateResponse, KvStoreListResponse +``` + +Methods: + +- client.fastedge.kv_stores.create(\*\*params) -> KvStoreCreateResponse +- client.fastedge.kv_stores.list(\*\*params) -> KvStoreListResponse +- client.fastedge.kv_stores.delete(id) -> None +- client.fastedge.kv_stores.get(id) -> KvStore +- client.fastedge.kv_stores.replace(id, \*\*params) -> KvStore diff --git a/src/gcore/resources/fastedge/apps/__init__.py b/src/gcore/resources/fastedge/apps/__init__.py new file mode 100644 index 00000000..fe734f02 --- /dev/null +++ b/src/gcore/resources/fastedge/apps/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .apps import ( + AppsResource, + AsyncAppsResource, + AppsResourceWithRawResponse, + AsyncAppsResourceWithRawResponse, + AppsResourceWithStreamingResponse, + AsyncAppsResourceWithStreamingResponse, +) +from .logs import ( + LogsResource, + AsyncLogsResource, + LogsResourceWithRawResponse, + AsyncLogsResourceWithRawResponse, + LogsResourceWithStreamingResponse, + AsyncLogsResourceWithStreamingResponse, +) + +__all__ = [ + "LogsResource", + "AsyncLogsResource", + "LogsResourceWithRawResponse", + "AsyncLogsResourceWithRawResponse", + "LogsResourceWithStreamingResponse", + "AsyncLogsResourceWithStreamingResponse", + "AppsResource", + "AsyncAppsResource", + "AppsResourceWithRawResponse", + "AsyncAppsResourceWithRawResponse", + "AppsResourceWithStreamingResponse", + "AsyncAppsResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/fastedge/apps/apps.py b/src/gcore/resources/fastedge/apps/apps.py new file mode 100644 index 00000000..c415ced9 --- /dev/null +++ b/src/gcore/resources/fastedge/apps/apps.py @@ -0,0 +1,932 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Literal + +import httpx + +from .logs import ( + LogsResource, + AsyncLogsResource, + LogsResourceWithRawResponse, + AsyncLogsResourceWithRawResponse, + LogsResourceWithStreamingResponse, + AsyncLogsResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPageFastedgeApps, AsyncOffsetPageFastedgeApps +from ...._base_client import AsyncPaginator, make_request_options +from ....types.fastedge import app_list_params, app_create_params, app_update_params, app_replace_params +from ....types.fastedge.app import App +from ....types.fastedge.app_short import AppShort + +__all__ = ["AppsResource", "AsyncAppsResource"] + + +class AppsResource(SyncAPIResource): + @cached_property + def logs(self) -> LogsResource: + return LogsResource(self._client) + + @cached_property + def with_raw_response(self) -> AppsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AppsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AppsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AppsResourceWithStreamingResponse(self) + + def create( + self, + *, + binary: int | Omit = omit, + comment: str | Omit = omit, + debug: bool | Omit = omit, + env: Dict[str, str] | Omit = omit, + log: Optional[Literal["kafka", "none"]] | Omit = omit, + name: str | Omit = omit, + rsp_headers: Dict[str, str] | Omit = omit, + secrets: Dict[str, app_create_params.Secrets] | Omit = omit, + status: int | Omit = omit, + stores: Dict[str, app_create_params.Stores] | Omit = omit, + template: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AppShort: + """ + Add a new app + + Args: + binary: Binary ID + + comment: App description + + debug: Switch on logging for 30 minutes (switched off by default) + + env: Environment variables + + log: Logging channel (by default - kafka, which allows exploring logs with API) + + name: App name + + rsp_headers: Extra headers to add to the response + + secrets: Application secrets + + status: + Status code: + 0 - draft (inactive) + 1 - enabled + 2 - disabled + 3 - hourly call limit exceeded + 4 - daily call limit exceeded + 5 - suspended + + stores: Application edge stores + + template: Template ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/fastedge/v1/apps", + body=maybe_transform( + { + "binary": binary, + "comment": comment, + "debug": debug, + "env": env, + "log": log, + "name": name, + "rsp_headers": rsp_headers, + "secrets": secrets, + "status": status, + "stores": stores, + "template": template, + }, + app_create_params.AppCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppShort, + ) + + def update( + self, + id: int, + *, + binary: int | Omit = omit, + comment: str | Omit = omit, + debug: bool | Omit = omit, + env: Dict[str, str] | Omit = omit, + log: Optional[Literal["kafka", "none"]] | Omit = omit, + name: str | Omit = omit, + rsp_headers: Dict[str, str] | Omit = omit, + secrets: Dict[str, app_update_params.Secrets] | Omit = omit, + status: int | Omit = omit, + stores: Dict[str, app_update_params.Stores] | Omit = omit, + template: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AppShort: + """ + Update app + + Args: + binary: Binary ID + + comment: App description + + debug: Switch on logging for 30 minutes (switched off by default) + + env: Environment variables + + log: Logging channel (by default - kafka, which allows exploring logs with API) + + name: App name + + rsp_headers: Extra headers to add to the response + + secrets: Application secrets + + status: + Status code: + 0 - draft (inactive) + 1 - enabled + 2 - disabled + 3 - hourly call limit exceeded + 4 - daily call limit exceeded + 5 - suspended + + stores: Application edge stores + + template: Template ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/fastedge/v1/apps/{id}", + body=maybe_transform( + { + "binary": binary, + "comment": comment, + "debug": debug, + "env": env, + "log": log, + "name": name, + "rsp_headers": rsp_headers, + "secrets": secrets, + "status": status, + "stores": stores, + "template": template, + }, + app_update_params.AppUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppShort, + ) + + def list( + self, + *, + api_type: Literal["wasi-http", "proxy-wasm"] | Omit = omit, + binary: int | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Literal[ + "name", + "-name", + "status", + "-status", + "id", + "-id", + "template", + "-template", + "binary", + "-binary", + "plan", + "-plan", + ] + | Omit = omit, + plan: int | Omit = omit, + status: int | Omit = omit, + template: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPageFastedgeApps[AppShort]: + """ + List client's apps + + Args: + api_type: + API type: + wasi-http - WASI with HTTP entry point + proxy-wasm - Proxy-Wasm app, callable from CDN + + binary: Binary ID + + limit: Limit for pagination + + name: Name of the app + + offset: Offset for pagination + + ordering: Ordering + + plan: Plan ID + + status: + Status code: + 0 - draft (inactive) + 1 - enabled + 2 - disabled + 3 - hourly call limit exceeded + 4 - daily call limit exceeded + 5 - suspended + + template: Template ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/fastedge/v1/apps", + page=SyncOffsetPageFastedgeApps[AppShort], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "api_type": api_type, + "binary": binary, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + "plan": plan, + "status": status, + "template": template, + }, + app_list_params.AppListParams, + ), + ), + model=AppShort, + ) + + def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete app + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/fastedge/v1/apps/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> App: + """ + Get app details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/fastedge/v1/apps/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=App, + ) + + def replace( + self, + id: int, + *, + body: app_replace_params.Body | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AppShort: + """ + Update an app + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/fastedge/v1/apps/{id}", + body=maybe_transform(body, app_replace_params.AppReplaceParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppShort, + ) + + +class AsyncAppsResource(AsyncAPIResource): + @cached_property + def logs(self) -> AsyncLogsResource: + return AsyncLogsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncAppsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncAppsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAppsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncAppsResourceWithStreamingResponse(self) + + async def create( + self, + *, + binary: int | Omit = omit, + comment: str | Omit = omit, + debug: bool | Omit = omit, + env: Dict[str, str] | Omit = omit, + log: Optional[Literal["kafka", "none"]] | Omit = omit, + name: str | Omit = omit, + rsp_headers: Dict[str, str] | Omit = omit, + secrets: Dict[str, app_create_params.Secrets] | Omit = omit, + status: int | Omit = omit, + stores: Dict[str, app_create_params.Stores] | Omit = omit, + template: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AppShort: + """ + Add a new app + + Args: + binary: Binary ID + + comment: App description + + debug: Switch on logging for 30 minutes (switched off by default) + + env: Environment variables + + log: Logging channel (by default - kafka, which allows exploring logs with API) + + name: App name + + rsp_headers: Extra headers to add to the response + + secrets: Application secrets + + status: + Status code: + 0 - draft (inactive) + 1 - enabled + 2 - disabled + 3 - hourly call limit exceeded + 4 - daily call limit exceeded + 5 - suspended + + stores: Application edge stores + + template: Template ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/fastedge/v1/apps", + body=await async_maybe_transform( + { + "binary": binary, + "comment": comment, + "debug": debug, + "env": env, + "log": log, + "name": name, + "rsp_headers": rsp_headers, + "secrets": secrets, + "status": status, + "stores": stores, + "template": template, + }, + app_create_params.AppCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppShort, + ) + + async def update( + self, + id: int, + *, + binary: int | Omit = omit, + comment: str | Omit = omit, + debug: bool | Omit = omit, + env: Dict[str, str] | Omit = omit, + log: Optional[Literal["kafka", "none"]] | Omit = omit, + name: str | Omit = omit, + rsp_headers: Dict[str, str] | Omit = omit, + secrets: Dict[str, app_update_params.Secrets] | Omit = omit, + status: int | Omit = omit, + stores: Dict[str, app_update_params.Stores] | Omit = omit, + template: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AppShort: + """ + Update app + + Args: + binary: Binary ID + + comment: App description + + debug: Switch on logging for 30 minutes (switched off by default) + + env: Environment variables + + log: Logging channel (by default - kafka, which allows exploring logs with API) + + name: App name + + rsp_headers: Extra headers to add to the response + + secrets: Application secrets + + status: + Status code: + 0 - draft (inactive) + 1 - enabled + 2 - disabled + 3 - hourly call limit exceeded + 4 - daily call limit exceeded + 5 - suspended + + stores: Application edge stores + + template: Template ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/fastedge/v1/apps/{id}", + body=await async_maybe_transform( + { + "binary": binary, + "comment": comment, + "debug": debug, + "env": env, + "log": log, + "name": name, + "rsp_headers": rsp_headers, + "secrets": secrets, + "status": status, + "stores": stores, + "template": template, + }, + app_update_params.AppUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppShort, + ) + + def list( + self, + *, + api_type: Literal["wasi-http", "proxy-wasm"] | Omit = omit, + binary: int | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Literal[ + "name", + "-name", + "status", + "-status", + "id", + "-id", + "template", + "-template", + "binary", + "-binary", + "plan", + "-plan", + ] + | Omit = omit, + plan: int | Omit = omit, + status: int | Omit = omit, + template: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[AppShort, AsyncOffsetPageFastedgeApps[AppShort]]: + """ + List client's apps + + Args: + api_type: + API type: + wasi-http - WASI with HTTP entry point + proxy-wasm - Proxy-Wasm app, callable from CDN + + binary: Binary ID + + limit: Limit for pagination + + name: Name of the app + + offset: Offset for pagination + + ordering: Ordering + + plan: Plan ID + + status: + Status code: + 0 - draft (inactive) + 1 - enabled + 2 - disabled + 3 - hourly call limit exceeded + 4 - daily call limit exceeded + 5 - suspended + + template: Template ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/fastedge/v1/apps", + page=AsyncOffsetPageFastedgeApps[AppShort], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "api_type": api_type, + "binary": binary, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + "plan": plan, + "status": status, + "template": template, + }, + app_list_params.AppListParams, + ), + ), + model=AppShort, + ) + + async def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete app + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/fastedge/v1/apps/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> App: + """ + Get app details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/fastedge/v1/apps/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=App, + ) + + async def replace( + self, + id: int, + *, + body: app_replace_params.Body | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AppShort: + """ + Update an app + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/fastedge/v1/apps/{id}", + body=await async_maybe_transform(body, app_replace_params.AppReplaceParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppShort, + ) + + +class AppsResourceWithRawResponse: + def __init__(self, apps: AppsResource) -> None: + self._apps = apps + + self.create = to_raw_response_wrapper( + apps.create, + ) + self.update = to_raw_response_wrapper( + apps.update, + ) + self.list = to_raw_response_wrapper( + apps.list, + ) + self.delete = to_raw_response_wrapper( + apps.delete, + ) + self.get = to_raw_response_wrapper( + apps.get, + ) + self.replace = to_raw_response_wrapper( + apps.replace, + ) + + @cached_property + def logs(self) -> LogsResourceWithRawResponse: + return LogsResourceWithRawResponse(self._apps.logs) + + +class AsyncAppsResourceWithRawResponse: + def __init__(self, apps: AsyncAppsResource) -> None: + self._apps = apps + + self.create = async_to_raw_response_wrapper( + apps.create, + ) + self.update = async_to_raw_response_wrapper( + apps.update, + ) + self.list = async_to_raw_response_wrapper( + apps.list, + ) + self.delete = async_to_raw_response_wrapper( + apps.delete, + ) + self.get = async_to_raw_response_wrapper( + apps.get, + ) + self.replace = async_to_raw_response_wrapper( + apps.replace, + ) + + @cached_property + def logs(self) -> AsyncLogsResourceWithRawResponse: + return AsyncLogsResourceWithRawResponse(self._apps.logs) + + +class AppsResourceWithStreamingResponse: + def __init__(self, apps: AppsResource) -> None: + self._apps = apps + + self.create = to_streamed_response_wrapper( + apps.create, + ) + self.update = to_streamed_response_wrapper( + apps.update, + ) + self.list = to_streamed_response_wrapper( + apps.list, + ) + self.delete = to_streamed_response_wrapper( + apps.delete, + ) + self.get = to_streamed_response_wrapper( + apps.get, + ) + self.replace = to_streamed_response_wrapper( + apps.replace, + ) + + @cached_property + def logs(self) -> LogsResourceWithStreamingResponse: + return LogsResourceWithStreamingResponse(self._apps.logs) + + +class AsyncAppsResourceWithStreamingResponse: + def __init__(self, apps: AsyncAppsResource) -> None: + self._apps = apps + + self.create = async_to_streamed_response_wrapper( + apps.create, + ) + self.update = async_to_streamed_response_wrapper( + apps.update, + ) + self.list = async_to_streamed_response_wrapper( + apps.list, + ) + self.delete = async_to_streamed_response_wrapper( + apps.delete, + ) + self.get = async_to_streamed_response_wrapper( + apps.get, + ) + self.replace = async_to_streamed_response_wrapper( + apps.replace, + ) + + @cached_property + def logs(self) -> AsyncLogsResourceWithStreamingResponse: + return AsyncLogsResourceWithStreamingResponse(self._apps.logs) diff --git a/src/gcore/resources/fastedge/apps/logs.py b/src/gcore/resources/fastedge/apps/logs.py new file mode 100644 index 00000000..8f589ab0 --- /dev/null +++ b/src/gcore/resources/fastedge/apps/logs.py @@ -0,0 +1,248 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPageFastedgeAppLogs, AsyncOffsetPageFastedgeAppLogs +from ...._base_client import AsyncPaginator, make_request_options +from ....types.fastedge.apps import log_list_params +from ....types.fastedge.apps.log import Log + +__all__ = ["LogsResource", "AsyncLogsResource"] + + +class LogsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> LogsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return LogsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> LogsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return LogsResourceWithStreamingResponse(self) + + def list( + self, + id: int, + *, + client_ip: str | Omit = omit, + edge: str | Omit = omit, + from_: Union[str, datetime] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + search: str | Omit = omit, + sort: Literal["desc", "asc"] | Omit = omit, + to: Union[str, datetime] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPageFastedgeAppLogs[Log]: + """ + List logs for the app + + Args: + client_ip: Search by client IP + + edge: Edge name + + from_: Reporting period start time, RFC3339 format. Default 1 hour ago. + + limit: Limit for pagination + + offset: Offset for pagination + + search: Search string + + sort: Sort order (default desc) + + to: Reporting period end time, RFC3339 format. Default current time in UTC. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/fastedge/v1/apps/{id}/logs", + page=SyncOffsetPageFastedgeAppLogs[Log], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "client_ip": client_ip, + "edge": edge, + "from_": from_, + "limit": limit, + "offset": offset, + "search": search, + "sort": sort, + "to": to, + }, + log_list_params.LogListParams, + ), + ), + model=Log, + ) + + +class AsyncLogsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncLogsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncLogsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncLogsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncLogsResourceWithStreamingResponse(self) + + def list( + self, + id: int, + *, + client_ip: str | Omit = omit, + edge: str | Omit = omit, + from_: Union[str, datetime] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + search: str | Omit = omit, + sort: Literal["desc", "asc"] | Omit = omit, + to: Union[str, datetime] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Log, AsyncOffsetPageFastedgeAppLogs[Log]]: + """ + List logs for the app + + Args: + client_ip: Search by client IP + + edge: Edge name + + from_: Reporting period start time, RFC3339 format. Default 1 hour ago. + + limit: Limit for pagination + + offset: Offset for pagination + + search: Search string + + sort: Sort order (default desc) + + to: Reporting period end time, RFC3339 format. Default current time in UTC. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/fastedge/v1/apps/{id}/logs", + page=AsyncOffsetPageFastedgeAppLogs[Log], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "client_ip": client_ip, + "edge": edge, + "from_": from_, + "limit": limit, + "offset": offset, + "search": search, + "sort": sort, + "to": to, + }, + log_list_params.LogListParams, + ), + ), + model=Log, + ) + + +class LogsResourceWithRawResponse: + def __init__(self, logs: LogsResource) -> None: + self._logs = logs + + self.list = to_raw_response_wrapper( + logs.list, + ) + + +class AsyncLogsResourceWithRawResponse: + def __init__(self, logs: AsyncLogsResource) -> None: + self._logs = logs + + self.list = async_to_raw_response_wrapper( + logs.list, + ) + + +class LogsResourceWithStreamingResponse: + def __init__(self, logs: LogsResource) -> None: + self._logs = logs + + self.list = to_streamed_response_wrapper( + logs.list, + ) + + +class AsyncLogsResourceWithStreamingResponse: + def __init__(self, logs: AsyncLogsResource) -> None: + self._logs = logs + + self.list = async_to_streamed_response_wrapper( + logs.list, + ) diff --git a/src/gcore/resources/fastedge/binaries.py b/src/gcore/resources/fastedge/binaries.py new file mode 100644 index 00000000..1fe86c54 --- /dev/null +++ b/src/gcore/resources/fastedge/binaries.py @@ -0,0 +1,378 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os + +import httpx + +from ..._files import read_file_content, async_read_file_content +from ..._types import ( + Body, + Query, + Headers, + NoneType, + NotGiven, + BinaryTypes, + FileContent, + AsyncBinaryTypes, + not_given, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.fastedge.binary import Binary +from ...types.fastedge.binary_short import BinaryShort +from ...types.fastedge.binary_list_response import BinaryListResponse + +__all__ = ["BinariesResource", "AsyncBinariesResource"] + + +class BinariesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> BinariesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return BinariesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BinariesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return BinariesResourceWithStreamingResponse(self) + + def create( + self, + body: FileContent | BinaryTypes, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BinaryShort: + """ + Store compiled WASM binary + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Content-Type": "application/octet-stream", **(extra_headers or {})} + return self._post( + "/fastedge/v1/binaries/raw", + content=read_file_content(body) if isinstance(body, os.PathLike) else body, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BinaryShort, + ) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BinaryListResponse: + """List binaries""" + return self._get( + "/fastedge/v1/binaries", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BinaryListResponse, + ) + + def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a binary + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/fastedge/v1/binaries/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Binary: + """ + Get binary + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/fastedge/v1/binaries/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Binary, + ) + + +class AsyncBinariesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncBinariesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncBinariesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBinariesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncBinariesResourceWithStreamingResponse(self) + + async def create( + self, + body: FileContent | AsyncBinaryTypes, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BinaryShort: + """ + Store compiled WASM binary + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Content-Type": "application/octet-stream", **(extra_headers or {})} + return await self._post( + "/fastedge/v1/binaries/raw", + content=await async_read_file_content(body) if isinstance(body, os.PathLike) else body, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BinaryShort, + ) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BinaryListResponse: + """List binaries""" + return await self._get( + "/fastedge/v1/binaries", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BinaryListResponse, + ) + + async def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a binary + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/fastedge/v1/binaries/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Binary: + """ + Get binary + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/fastedge/v1/binaries/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Binary, + ) + + +class BinariesResourceWithRawResponse: + def __init__(self, binaries: BinariesResource) -> None: + self._binaries = binaries + + self.create = to_raw_response_wrapper( + binaries.create, + ) + self.list = to_raw_response_wrapper( + binaries.list, + ) + self.delete = to_raw_response_wrapper( + binaries.delete, + ) + self.get = to_raw_response_wrapper( + binaries.get, + ) + + +class AsyncBinariesResourceWithRawResponse: + def __init__(self, binaries: AsyncBinariesResource) -> None: + self._binaries = binaries + + self.create = async_to_raw_response_wrapper( + binaries.create, + ) + self.list = async_to_raw_response_wrapper( + binaries.list, + ) + self.delete = async_to_raw_response_wrapper( + binaries.delete, + ) + self.get = async_to_raw_response_wrapper( + binaries.get, + ) + + +class BinariesResourceWithStreamingResponse: + def __init__(self, binaries: BinariesResource) -> None: + self._binaries = binaries + + self.create = to_streamed_response_wrapper( + binaries.create, + ) + self.list = to_streamed_response_wrapper( + binaries.list, + ) + self.delete = to_streamed_response_wrapper( + binaries.delete, + ) + self.get = to_streamed_response_wrapper( + binaries.get, + ) + + +class AsyncBinariesResourceWithStreamingResponse: + def __init__(self, binaries: AsyncBinariesResource) -> None: + self._binaries = binaries + + self.create = async_to_streamed_response_wrapper( + binaries.create, + ) + self.list = async_to_streamed_response_wrapper( + binaries.list, + ) + self.delete = async_to_streamed_response_wrapper( + binaries.delete, + ) + self.get = async_to_streamed_response_wrapper( + binaries.get, + ) diff --git a/src/gcore/resources/fastedge/fastedge.py b/src/gcore/resources/fastedge/fastedge.py new file mode 100644 index 00000000..d4ba7cf3 --- /dev/null +++ b/src/gcore/resources/fastedge/fastedge.py @@ -0,0 +1,327 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .secrets import ( + SecretsResource, + AsyncSecretsResource, + SecretsResourceWithRawResponse, + AsyncSecretsResourceWithRawResponse, + SecretsResourceWithStreamingResponse, + AsyncSecretsResourceWithStreamingResponse, +) +from ..._types import Body, Query, Headers, NotGiven, not_given +from .binaries import ( + BinariesResource, + AsyncBinariesResource, + BinariesResourceWithRawResponse, + AsyncBinariesResourceWithRawResponse, + BinariesResourceWithStreamingResponse, + AsyncBinariesResourceWithStreamingResponse, +) +from ..._compat import cached_property +from .apps.apps import ( + AppsResource, + AsyncAppsResource, + AppsResourceWithRawResponse, + AsyncAppsResourceWithRawResponse, + AppsResourceWithStreamingResponse, + AsyncAppsResourceWithStreamingResponse, +) +from .kv_stores import ( + KvStoresResource, + AsyncKvStoresResource, + KvStoresResourceWithRawResponse, + AsyncKvStoresResourceWithRawResponse, + KvStoresResourceWithStreamingResponse, + AsyncKvStoresResourceWithStreamingResponse, +) +from .templates import ( + TemplatesResource, + AsyncTemplatesResource, + TemplatesResourceWithRawResponse, + AsyncTemplatesResourceWithRawResponse, + TemplatesResourceWithStreamingResponse, + AsyncTemplatesResourceWithStreamingResponse, +) +from .statistics import ( + StatisticsResource, + AsyncStatisticsResource, + StatisticsResourceWithRawResponse, + AsyncStatisticsResourceWithRawResponse, + StatisticsResourceWithStreamingResponse, + AsyncStatisticsResourceWithStreamingResponse, +) +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.fastedge.client import Client + +__all__ = ["FastedgeResource", "AsyncFastedgeResource"] + + +class FastedgeResource(SyncAPIResource): + @cached_property + def templates(self) -> TemplatesResource: + return TemplatesResource(self._client) + + @cached_property + def secrets(self) -> SecretsResource: + return SecretsResource(self._client) + + @cached_property + def binaries(self) -> BinariesResource: + return BinariesResource(self._client) + + @cached_property + def statistics(self) -> StatisticsResource: + return StatisticsResource(self._client) + + @cached_property + def apps(self) -> AppsResource: + return AppsResource(self._client) + + @cached_property + def kv_stores(self) -> KvStoresResource: + return KvStoresResource(self._client) + + @cached_property + def with_raw_response(self) -> FastedgeResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return FastedgeResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FastedgeResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return FastedgeResourceWithStreamingResponse(self) + + def get_account_overview( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Client: + """Get status and limits for the client""" + return self._get( + "/fastedge/v1/me", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Client, + ) + + +class AsyncFastedgeResource(AsyncAPIResource): + @cached_property + def templates(self) -> AsyncTemplatesResource: + return AsyncTemplatesResource(self._client) + + @cached_property + def secrets(self) -> AsyncSecretsResource: + return AsyncSecretsResource(self._client) + + @cached_property + def binaries(self) -> AsyncBinariesResource: + return AsyncBinariesResource(self._client) + + @cached_property + def statistics(self) -> AsyncStatisticsResource: + return AsyncStatisticsResource(self._client) + + @cached_property + def apps(self) -> AsyncAppsResource: + return AsyncAppsResource(self._client) + + @cached_property + def kv_stores(self) -> AsyncKvStoresResource: + return AsyncKvStoresResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncFastedgeResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncFastedgeResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFastedgeResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncFastedgeResourceWithStreamingResponse(self) + + async def get_account_overview( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Client: + """Get status and limits for the client""" + return await self._get( + "/fastedge/v1/me", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Client, + ) + + +class FastedgeResourceWithRawResponse: + def __init__(self, fastedge: FastedgeResource) -> None: + self._fastedge = fastedge + + self.get_account_overview = to_raw_response_wrapper( + fastedge.get_account_overview, + ) + + @cached_property + def templates(self) -> TemplatesResourceWithRawResponse: + return TemplatesResourceWithRawResponse(self._fastedge.templates) + + @cached_property + def secrets(self) -> SecretsResourceWithRawResponse: + return SecretsResourceWithRawResponse(self._fastedge.secrets) + + @cached_property + def binaries(self) -> BinariesResourceWithRawResponse: + return BinariesResourceWithRawResponse(self._fastedge.binaries) + + @cached_property + def statistics(self) -> StatisticsResourceWithRawResponse: + return StatisticsResourceWithRawResponse(self._fastedge.statistics) + + @cached_property + def apps(self) -> AppsResourceWithRawResponse: + return AppsResourceWithRawResponse(self._fastedge.apps) + + @cached_property + def kv_stores(self) -> KvStoresResourceWithRawResponse: + return KvStoresResourceWithRawResponse(self._fastedge.kv_stores) + + +class AsyncFastedgeResourceWithRawResponse: + def __init__(self, fastedge: AsyncFastedgeResource) -> None: + self._fastedge = fastedge + + self.get_account_overview = async_to_raw_response_wrapper( + fastedge.get_account_overview, + ) + + @cached_property + def templates(self) -> AsyncTemplatesResourceWithRawResponse: + return AsyncTemplatesResourceWithRawResponse(self._fastedge.templates) + + @cached_property + def secrets(self) -> AsyncSecretsResourceWithRawResponse: + return AsyncSecretsResourceWithRawResponse(self._fastedge.secrets) + + @cached_property + def binaries(self) -> AsyncBinariesResourceWithRawResponse: + return AsyncBinariesResourceWithRawResponse(self._fastedge.binaries) + + @cached_property + def statistics(self) -> AsyncStatisticsResourceWithRawResponse: + return AsyncStatisticsResourceWithRawResponse(self._fastedge.statistics) + + @cached_property + def apps(self) -> AsyncAppsResourceWithRawResponse: + return AsyncAppsResourceWithRawResponse(self._fastedge.apps) + + @cached_property + def kv_stores(self) -> AsyncKvStoresResourceWithRawResponse: + return AsyncKvStoresResourceWithRawResponse(self._fastedge.kv_stores) + + +class FastedgeResourceWithStreamingResponse: + def __init__(self, fastedge: FastedgeResource) -> None: + self._fastedge = fastedge + + self.get_account_overview = to_streamed_response_wrapper( + fastedge.get_account_overview, + ) + + @cached_property + def templates(self) -> TemplatesResourceWithStreamingResponse: + return TemplatesResourceWithStreamingResponse(self._fastedge.templates) + + @cached_property + def secrets(self) -> SecretsResourceWithStreamingResponse: + return SecretsResourceWithStreamingResponse(self._fastedge.secrets) + + @cached_property + def binaries(self) -> BinariesResourceWithStreamingResponse: + return BinariesResourceWithStreamingResponse(self._fastedge.binaries) + + @cached_property + def statistics(self) -> StatisticsResourceWithStreamingResponse: + return StatisticsResourceWithStreamingResponse(self._fastedge.statistics) + + @cached_property + def apps(self) -> AppsResourceWithStreamingResponse: + return AppsResourceWithStreamingResponse(self._fastedge.apps) + + @cached_property + def kv_stores(self) -> KvStoresResourceWithStreamingResponse: + return KvStoresResourceWithStreamingResponse(self._fastedge.kv_stores) + + +class AsyncFastedgeResourceWithStreamingResponse: + def __init__(self, fastedge: AsyncFastedgeResource) -> None: + self._fastedge = fastedge + + self.get_account_overview = async_to_streamed_response_wrapper( + fastedge.get_account_overview, + ) + + @cached_property + def templates(self) -> AsyncTemplatesResourceWithStreamingResponse: + return AsyncTemplatesResourceWithStreamingResponse(self._fastedge.templates) + + @cached_property + def secrets(self) -> AsyncSecretsResourceWithStreamingResponse: + return AsyncSecretsResourceWithStreamingResponse(self._fastedge.secrets) + + @cached_property + def binaries(self) -> AsyncBinariesResourceWithStreamingResponse: + return AsyncBinariesResourceWithStreamingResponse(self._fastedge.binaries) + + @cached_property + def statistics(self) -> AsyncStatisticsResourceWithStreamingResponse: + return AsyncStatisticsResourceWithStreamingResponse(self._fastedge.statistics) + + @cached_property + def apps(self) -> AsyncAppsResourceWithStreamingResponse: + return AsyncAppsResourceWithStreamingResponse(self._fastedge.apps) + + @cached_property + def kv_stores(self) -> AsyncKvStoresResourceWithStreamingResponse: + return AsyncKvStoresResourceWithStreamingResponse(self._fastedge.kv_stores) diff --git a/src/gcore/resources/fastedge/kv_stores.py b/src/gcore/resources/fastedge/kv_stores.py new file mode 100644 index 00000000..34e59741 --- /dev/null +++ b/src/gcore/resources/fastedge/kv_stores.py @@ -0,0 +1,565 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.fastedge import kv_store_list_params, kv_store_create_params, kv_store_replace_params +from ...types.fastedge.kv_store import KvStore +from ...types.fastedge.kv_store_list_response import KvStoreListResponse +from ...types.fastedge.kv_store_create_response import KvStoreCreateResponse + +__all__ = ["KvStoresResource", "AsyncKvStoresResource"] + + +class KvStoresResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> KvStoresResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return KvStoresResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> KvStoresResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return KvStoresResourceWithStreamingResponse(self) + + def create( + self, + *, + name: str, + byod: kv_store_create_params.Byod | Omit = omit, + comment: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> KvStoreCreateResponse: + """ + Add a new Edge store + + Args: + name: A name of the store + + byod: BYOD (Bring Your Own Data) settings + + comment: A description of the store + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/fastedge/v1/kv", + body=maybe_transform( + { + "name": name, + "byod": byod, + "comment": comment, + }, + kv_store_create_params.KvStoreCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=KvStoreCreateResponse, + ) + + def list( + self, + *, + app_id: int | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> KvStoreListResponse: + """ + List available edge stores + + Args: + app_id: App ID + + limit: Limit for pagination + + offset: Offset for pagination + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/fastedge/v1/kv", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "app_id": app_id, + "limit": limit, + "offset": offset, + }, + kv_store_list_params.KvStoreListParams, + ), + ), + cast_to=KvStoreListResponse, + ) + + def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a store + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/fastedge/v1/kv/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> KvStore: + """ + Get the edge store by id + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/fastedge/v1/kv/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=KvStore, + ) + + def replace( + self, + id: int, + *, + name: str, + byod: kv_store_replace_params.Byod | Omit = omit, + comment: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> KvStore: + """ + Update a store + + Args: + name: A name of the store + + byod: BYOD (Bring Your Own Data) settings + + comment: A description of the store + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/fastedge/v1/kv/{id}", + body=maybe_transform( + { + "name": name, + "byod": byod, + "comment": comment, + }, + kv_store_replace_params.KvStoreReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=KvStore, + ) + + +class AsyncKvStoresResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncKvStoresResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncKvStoresResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncKvStoresResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncKvStoresResourceWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + byod: kv_store_create_params.Byod | Omit = omit, + comment: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> KvStoreCreateResponse: + """ + Add a new Edge store + + Args: + name: A name of the store + + byod: BYOD (Bring Your Own Data) settings + + comment: A description of the store + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/fastedge/v1/kv", + body=await async_maybe_transform( + { + "name": name, + "byod": byod, + "comment": comment, + }, + kv_store_create_params.KvStoreCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=KvStoreCreateResponse, + ) + + async def list( + self, + *, + app_id: int | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> KvStoreListResponse: + """ + List available edge stores + + Args: + app_id: App ID + + limit: Limit for pagination + + offset: Offset for pagination + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/fastedge/v1/kv", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "app_id": app_id, + "limit": limit, + "offset": offset, + }, + kv_store_list_params.KvStoreListParams, + ), + ), + cast_to=KvStoreListResponse, + ) + + async def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a store + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/fastedge/v1/kv/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> KvStore: + """ + Get the edge store by id + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/fastedge/v1/kv/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=KvStore, + ) + + async def replace( + self, + id: int, + *, + name: str, + byod: kv_store_replace_params.Byod | Omit = omit, + comment: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> KvStore: + """ + Update a store + + Args: + name: A name of the store + + byod: BYOD (Bring Your Own Data) settings + + comment: A description of the store + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/fastedge/v1/kv/{id}", + body=await async_maybe_transform( + { + "name": name, + "byod": byod, + "comment": comment, + }, + kv_store_replace_params.KvStoreReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=KvStore, + ) + + +class KvStoresResourceWithRawResponse: + def __init__(self, kv_stores: KvStoresResource) -> None: + self._kv_stores = kv_stores + + self.create = to_raw_response_wrapper( + kv_stores.create, + ) + self.list = to_raw_response_wrapper( + kv_stores.list, + ) + self.delete = to_raw_response_wrapper( + kv_stores.delete, + ) + self.get = to_raw_response_wrapper( + kv_stores.get, + ) + self.replace = to_raw_response_wrapper( + kv_stores.replace, + ) + + +class AsyncKvStoresResourceWithRawResponse: + def __init__(self, kv_stores: AsyncKvStoresResource) -> None: + self._kv_stores = kv_stores + + self.create = async_to_raw_response_wrapper( + kv_stores.create, + ) + self.list = async_to_raw_response_wrapper( + kv_stores.list, + ) + self.delete = async_to_raw_response_wrapper( + kv_stores.delete, + ) + self.get = async_to_raw_response_wrapper( + kv_stores.get, + ) + self.replace = async_to_raw_response_wrapper( + kv_stores.replace, + ) + + +class KvStoresResourceWithStreamingResponse: + def __init__(self, kv_stores: KvStoresResource) -> None: + self._kv_stores = kv_stores + + self.create = to_streamed_response_wrapper( + kv_stores.create, + ) + self.list = to_streamed_response_wrapper( + kv_stores.list, + ) + self.delete = to_streamed_response_wrapper( + kv_stores.delete, + ) + self.get = to_streamed_response_wrapper( + kv_stores.get, + ) + self.replace = to_streamed_response_wrapper( + kv_stores.replace, + ) + + +class AsyncKvStoresResourceWithStreamingResponse: + def __init__(self, kv_stores: AsyncKvStoresResource) -> None: + self._kv_stores = kv_stores + + self.create = async_to_streamed_response_wrapper( + kv_stores.create, + ) + self.list = async_to_streamed_response_wrapper( + kv_stores.list, + ) + self.delete = async_to_streamed_response_wrapper( + kv_stores.delete, + ) + self.get = async_to_streamed_response_wrapper( + kv_stores.get, + ) + self.replace = async_to_streamed_response_wrapper( + kv_stores.replace, + ) diff --git a/src/gcore/resources/fastedge/secrets.py b/src/gcore/resources/fastedge/secrets.py new file mode 100644 index 00000000..81685e61 --- /dev/null +++ b/src/gcore/resources/fastedge/secrets.py @@ -0,0 +1,687 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.fastedge import ( + secret_list_params, + secret_create_params, + secret_delete_params, + secret_update_params, + secret_replace_params, +) +from ...types.fastedge.secret import Secret +from ...types.fastedge.secret_list_response import SecretListResponse +from ...types.fastedge.secret_create_response import SecretCreateResponse + +__all__ = ["SecretsResource", "AsyncSecretsResource"] + + +class SecretsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SecretsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return SecretsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SecretsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return SecretsResourceWithStreamingResponse(self) + + def create( + self, + *, + name: str, + comment: str | Omit = omit, + secret_slots: Iterable[secret_create_params.SecretSlot] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecretCreateResponse: + """ + Add a new secret + + Args: + name: The unique name of the secret. + + comment: A description or comment about the secret. + + secret_slots: A list of secret slots associated with this secret. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/fastedge/v1/secrets", + body=maybe_transform( + { + "name": name, + "comment": comment, + "secret_slots": secret_slots, + }, + secret_create_params.SecretCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecretCreateResponse, + ) + + def update( + self, + id: int, + *, + comment: str | Omit = omit, + name: str | Omit = omit, + secret_slots: Iterable[secret_update_params.SecretSlot] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Secret: + """ + Update a secret + + Args: + comment: A description or comment about the secret. + + name: The unique name of the secret. + + secret_slots: A list of secret slots associated with this secret. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/fastedge/v1/secrets/{id}", + body=maybe_transform( + { + "comment": comment, + "name": name, + "secret_slots": secret_slots, + }, + secret_update_params.SecretUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Secret, + ) + + def list( + self, + *, + app_id: int | Omit = omit, + secret_name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecretListResponse: + """ + List available secrets + + Args: + app_id: App ID + + secret_name: Secret name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/fastedge/v1/secrets", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "app_id": app_id, + "secret_name": secret_name, + }, + secret_list_params.SecretListParams, + ), + ), + cast_to=SecretListResponse, + ) + + def delete( + self, + id: int, + *, + force: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a secret + + Args: + force: Force delete secret even if it is used in slots + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/fastedge/v1/secrets/{id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"force": force}, secret_delete_params.SecretDeleteParams), + ), + cast_to=NoneType, + ) + + def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Secret: + """ + Get secret by id + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/fastedge/v1/secrets/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Secret, + ) + + def replace( + self, + id: int, + *, + name: str, + comment: str | Omit = omit, + secret_slots: Iterable[secret_replace_params.SecretSlot] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Secret: + """ + Update a secret + + Args: + name: The unique name of the secret. + + comment: A description or comment about the secret. + + secret_slots: A list of secret slots associated with this secret. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/fastedge/v1/secrets/{id}", + body=maybe_transform( + { + "name": name, + "comment": comment, + "secret_slots": secret_slots, + }, + secret_replace_params.SecretReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Secret, + ) + + +class AsyncSecretsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSecretsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncSecretsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSecretsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncSecretsResourceWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + comment: str | Omit = omit, + secret_slots: Iterable[secret_create_params.SecretSlot] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecretCreateResponse: + """ + Add a new secret + + Args: + name: The unique name of the secret. + + comment: A description or comment about the secret. + + secret_slots: A list of secret slots associated with this secret. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/fastedge/v1/secrets", + body=await async_maybe_transform( + { + "name": name, + "comment": comment, + "secret_slots": secret_slots, + }, + secret_create_params.SecretCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SecretCreateResponse, + ) + + async def update( + self, + id: int, + *, + comment: str | Omit = omit, + name: str | Omit = omit, + secret_slots: Iterable[secret_update_params.SecretSlot] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Secret: + """ + Update a secret + + Args: + comment: A description or comment about the secret. + + name: The unique name of the secret. + + secret_slots: A list of secret slots associated with this secret. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/fastedge/v1/secrets/{id}", + body=await async_maybe_transform( + { + "comment": comment, + "name": name, + "secret_slots": secret_slots, + }, + secret_update_params.SecretUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Secret, + ) + + async def list( + self, + *, + app_id: int | Omit = omit, + secret_name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SecretListResponse: + """ + List available secrets + + Args: + app_id: App ID + + secret_name: Secret name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/fastedge/v1/secrets", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "app_id": app_id, + "secret_name": secret_name, + }, + secret_list_params.SecretListParams, + ), + ), + cast_to=SecretListResponse, + ) + + async def delete( + self, + id: int, + *, + force: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a secret + + Args: + force: Force delete secret even if it is used in slots + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/fastedge/v1/secrets/{id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"force": force}, secret_delete_params.SecretDeleteParams), + ), + cast_to=NoneType, + ) + + async def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Secret: + """ + Get secret by id + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/fastedge/v1/secrets/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Secret, + ) + + async def replace( + self, + id: int, + *, + name: str, + comment: str | Omit = omit, + secret_slots: Iterable[secret_replace_params.SecretSlot] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Secret: + """ + Update a secret + + Args: + name: The unique name of the secret. + + comment: A description or comment about the secret. + + secret_slots: A list of secret slots associated with this secret. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/fastedge/v1/secrets/{id}", + body=await async_maybe_transform( + { + "name": name, + "comment": comment, + "secret_slots": secret_slots, + }, + secret_replace_params.SecretReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Secret, + ) + + +class SecretsResourceWithRawResponse: + def __init__(self, secrets: SecretsResource) -> None: + self._secrets = secrets + + self.create = to_raw_response_wrapper( + secrets.create, + ) + self.update = to_raw_response_wrapper( + secrets.update, + ) + self.list = to_raw_response_wrapper( + secrets.list, + ) + self.delete = to_raw_response_wrapper( + secrets.delete, + ) + self.get = to_raw_response_wrapper( + secrets.get, + ) + self.replace = to_raw_response_wrapper( + secrets.replace, + ) + + +class AsyncSecretsResourceWithRawResponse: + def __init__(self, secrets: AsyncSecretsResource) -> None: + self._secrets = secrets + + self.create = async_to_raw_response_wrapper( + secrets.create, + ) + self.update = async_to_raw_response_wrapper( + secrets.update, + ) + self.list = async_to_raw_response_wrapper( + secrets.list, + ) + self.delete = async_to_raw_response_wrapper( + secrets.delete, + ) + self.get = async_to_raw_response_wrapper( + secrets.get, + ) + self.replace = async_to_raw_response_wrapper( + secrets.replace, + ) + + +class SecretsResourceWithStreamingResponse: + def __init__(self, secrets: SecretsResource) -> None: + self._secrets = secrets + + self.create = to_streamed_response_wrapper( + secrets.create, + ) + self.update = to_streamed_response_wrapper( + secrets.update, + ) + self.list = to_streamed_response_wrapper( + secrets.list, + ) + self.delete = to_streamed_response_wrapper( + secrets.delete, + ) + self.get = to_streamed_response_wrapper( + secrets.get, + ) + self.replace = to_streamed_response_wrapper( + secrets.replace, + ) + + +class AsyncSecretsResourceWithStreamingResponse: + def __init__(self, secrets: AsyncSecretsResource) -> None: + self._secrets = secrets + + self.create = async_to_streamed_response_wrapper( + secrets.create, + ) + self.update = async_to_streamed_response_wrapper( + secrets.update, + ) + self.list = async_to_streamed_response_wrapper( + secrets.list, + ) + self.delete = async_to_streamed_response_wrapper( + secrets.delete, + ) + self.get = async_to_streamed_response_wrapper( + secrets.get, + ) + self.replace = async_to_streamed_response_wrapper( + secrets.replace, + ) diff --git a/src/gcore/resources/fastedge/statistics.py b/src/gcore/resources/fastedge/statistics.py new file mode 100644 index 00000000..4b344931 --- /dev/null +++ b/src/gcore/resources/fastedge/statistics.py @@ -0,0 +1,347 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.fastedge import statistic_get_call_series_params, statistic_get_duration_series_params +from ...types.fastedge.statistic_get_call_series_response import StatisticGetCallSeriesResponse +from ...types.fastedge.statistic_get_duration_series_response import StatisticGetDurationSeriesResponse + +__all__ = ["StatisticsResource", "AsyncStatisticsResource"] + + +class StatisticsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> StatisticsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return StatisticsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> StatisticsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return StatisticsResourceWithStreamingResponse(self) + + def get_call_series( + self, + *, + from_: Union[str, datetime], + step: int, + to: Union[str, datetime], + id: int | Omit = omit, + network: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StatisticGetCallSeriesResponse: + """ + Call statistics + + Args: + from_: Reporting period start time, RFC3339 format + + step: Reporting granularity, in seconds + + to: Reporting period end time (not included into reporting period), RFC3339 format + + id: App ID + + network: Network name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/fastedge/v1/stats/calls", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "step": step, + "to": to, + "id": id, + "network": network, + }, + statistic_get_call_series_params.StatisticGetCallSeriesParams, + ), + ), + cast_to=StatisticGetCallSeriesResponse, + ) + + def get_duration_series( + self, + *, + from_: Union[str, datetime], + step: int, + to: Union[str, datetime], + id: int | Omit = omit, + network: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StatisticGetDurationSeriesResponse: + """ + Execution duration statistics + + Args: + from_: Reporting period start time, RFC3339 format + + step: Reporting granularity, in seconds + + to: Reporting period end time (not included into reporting period), RFC3339 format + + id: App ID + + network: Network name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/fastedge/v1/stats/app_duration", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "step": step, + "to": to, + "id": id, + "network": network, + }, + statistic_get_duration_series_params.StatisticGetDurationSeriesParams, + ), + ), + cast_to=StatisticGetDurationSeriesResponse, + ) + + +class AsyncStatisticsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncStatisticsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncStatisticsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncStatisticsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncStatisticsResourceWithStreamingResponse(self) + + async def get_call_series( + self, + *, + from_: Union[str, datetime], + step: int, + to: Union[str, datetime], + id: int | Omit = omit, + network: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StatisticGetCallSeriesResponse: + """ + Call statistics + + Args: + from_: Reporting period start time, RFC3339 format + + step: Reporting granularity, in seconds + + to: Reporting period end time (not included into reporting period), RFC3339 format + + id: App ID + + network: Network name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/fastedge/v1/stats/calls", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "step": step, + "to": to, + "id": id, + "network": network, + }, + statistic_get_call_series_params.StatisticGetCallSeriesParams, + ), + ), + cast_to=StatisticGetCallSeriesResponse, + ) + + async def get_duration_series( + self, + *, + from_: Union[str, datetime], + step: int, + to: Union[str, datetime], + id: int | Omit = omit, + network: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StatisticGetDurationSeriesResponse: + """ + Execution duration statistics + + Args: + from_: Reporting period start time, RFC3339 format + + step: Reporting granularity, in seconds + + to: Reporting period end time (not included into reporting period), RFC3339 format + + id: App ID + + network: Network name + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/fastedge/v1/stats/app_duration", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "step": step, + "to": to, + "id": id, + "network": network, + }, + statistic_get_duration_series_params.StatisticGetDurationSeriesParams, + ), + ), + cast_to=StatisticGetDurationSeriesResponse, + ) + + +class StatisticsResourceWithRawResponse: + def __init__(self, statistics: StatisticsResource) -> None: + self._statistics = statistics + + self.get_call_series = to_raw_response_wrapper( + statistics.get_call_series, + ) + self.get_duration_series = to_raw_response_wrapper( + statistics.get_duration_series, + ) + + +class AsyncStatisticsResourceWithRawResponse: + def __init__(self, statistics: AsyncStatisticsResource) -> None: + self._statistics = statistics + + self.get_call_series = async_to_raw_response_wrapper( + statistics.get_call_series, + ) + self.get_duration_series = async_to_raw_response_wrapper( + statistics.get_duration_series, + ) + + +class StatisticsResourceWithStreamingResponse: + def __init__(self, statistics: StatisticsResource) -> None: + self._statistics = statistics + + self.get_call_series = to_streamed_response_wrapper( + statistics.get_call_series, + ) + self.get_duration_series = to_streamed_response_wrapper( + statistics.get_duration_series, + ) + + +class AsyncStatisticsResourceWithStreamingResponse: + def __init__(self, statistics: AsyncStatisticsResource) -> None: + self._statistics = statistics + + self.get_call_series = async_to_streamed_response_wrapper( + statistics.get_call_series, + ) + self.get_duration_series = async_to_streamed_response_wrapper( + statistics.get_duration_series, + ) diff --git a/src/gcore/resources/fastedge/templates.py b/src/gcore/resources/fastedge/templates.py new file mode 100644 index 00000000..d58d3110 --- /dev/null +++ b/src/gcore/resources/fastedge/templates.py @@ -0,0 +1,652 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPageFastedgeTemplates, AsyncOffsetPageFastedgeTemplates +from ..._base_client import AsyncPaginator, make_request_options +from ...types.fastedge import ( + template_list_params, + template_create_params, + template_delete_params, + template_replace_params, +) +from ...types.fastedge.template import Template +from ...types.fastedge.template_short import TemplateShort +from ...types.fastedge.template_parameter_param import TemplateParameterParam + +__all__ = ["TemplatesResource", "AsyncTemplatesResource"] + + +class TemplatesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> TemplatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return TemplatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TemplatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return TemplatesResourceWithStreamingResponse(self) + + def create( + self, + *, + binary_id: int, + name: str, + owned: bool, + params: Iterable[TemplateParameterParam], + long_descr: str | Omit = omit, + short_descr: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TemplateShort: + """ + Add template + + Args: + binary_id: Binary ID + + name: Name of the template + + owned: Is the template owned by user? + + params: Parameters + + long_descr: Long description of the template + + short_descr: Short description of the template + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/fastedge/v1/template", + body=maybe_transform( + { + "binary_id": binary_id, + "name": name, + "owned": owned, + "params": params, + "long_descr": long_descr, + "short_descr": short_descr, + }, + template_create_params.TemplateCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TemplateShort, + ) + + def list( + self, + *, + api_type: Literal["wasi-http", "proxy-wasm"] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + only_mine: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPageFastedgeTemplates[TemplateShort]: + """ + List app templates + + Args: + api_type: + API type: + wasi-http - WASI with HTTP entry point + proxy-wasm - Proxy-Wasm app, callable from CDN + + limit: Limit for pagination + + offset: Offset for pagination + + only_mine: Only my templates + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/fastedge/v1/template", + page=SyncOffsetPageFastedgeTemplates[TemplateShort], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "api_type": api_type, + "limit": limit, + "offset": offset, + "only_mine": only_mine, + }, + template_list_params.TemplateListParams, + ), + ), + model=TemplateShort, + ) + + def delete( + self, + id: int, + *, + force: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete template + + Args: + force: Force template deletion even if it is shared to groups + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/fastedge/v1/template/{id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"force": force}, template_delete_params.TemplateDeleteParams), + ), + cast_to=NoneType, + ) + + def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Template: + """ + Get template details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/fastedge/v1/template/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Template, + ) + + def replace( + self, + id: int, + *, + binary_id: int, + name: str, + owned: bool, + params: Iterable[TemplateParameterParam], + long_descr: str | Omit = omit, + short_descr: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TemplateShort: + """ + Update template + + Args: + binary_id: Binary ID + + name: Name of the template + + owned: Is the template owned by user? + + params: Parameters + + long_descr: Long description of the template + + short_descr: Short description of the template + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/fastedge/v1/template/{id}", + body=maybe_transform( + { + "binary_id": binary_id, + "name": name, + "owned": owned, + "params": params, + "long_descr": long_descr, + "short_descr": short_descr, + }, + template_replace_params.TemplateReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TemplateShort, + ) + + +class AsyncTemplatesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncTemplatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncTemplatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTemplatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncTemplatesResourceWithStreamingResponse(self) + + async def create( + self, + *, + binary_id: int, + name: str, + owned: bool, + params: Iterable[TemplateParameterParam], + long_descr: str | Omit = omit, + short_descr: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TemplateShort: + """ + Add template + + Args: + binary_id: Binary ID + + name: Name of the template + + owned: Is the template owned by user? + + params: Parameters + + long_descr: Long description of the template + + short_descr: Short description of the template + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/fastedge/v1/template", + body=await async_maybe_transform( + { + "binary_id": binary_id, + "name": name, + "owned": owned, + "params": params, + "long_descr": long_descr, + "short_descr": short_descr, + }, + template_create_params.TemplateCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TemplateShort, + ) + + def list( + self, + *, + api_type: Literal["wasi-http", "proxy-wasm"] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + only_mine: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[TemplateShort, AsyncOffsetPageFastedgeTemplates[TemplateShort]]: + """ + List app templates + + Args: + api_type: + API type: + wasi-http - WASI with HTTP entry point + proxy-wasm - Proxy-Wasm app, callable from CDN + + limit: Limit for pagination + + offset: Offset for pagination + + only_mine: Only my templates + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/fastedge/v1/template", + page=AsyncOffsetPageFastedgeTemplates[TemplateShort], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "api_type": api_type, + "limit": limit, + "offset": offset, + "only_mine": only_mine, + }, + template_list_params.TemplateListParams, + ), + ), + model=TemplateShort, + ) + + async def delete( + self, + id: int, + *, + force: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete template + + Args: + force: Force template deletion even if it is shared to groups + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/fastedge/v1/template/{id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"force": force}, template_delete_params.TemplateDeleteParams), + ), + cast_to=NoneType, + ) + + async def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Template: + """ + Get template details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/fastedge/v1/template/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Template, + ) + + async def replace( + self, + id: int, + *, + binary_id: int, + name: str, + owned: bool, + params: Iterable[TemplateParameterParam], + long_descr: str | Omit = omit, + short_descr: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> TemplateShort: + """ + Update template + + Args: + binary_id: Binary ID + + name: Name of the template + + owned: Is the template owned by user? + + params: Parameters + + long_descr: Long description of the template + + short_descr: Short description of the template + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/fastedge/v1/template/{id}", + body=await async_maybe_transform( + { + "binary_id": binary_id, + "name": name, + "owned": owned, + "params": params, + "long_descr": long_descr, + "short_descr": short_descr, + }, + template_replace_params.TemplateReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TemplateShort, + ) + + +class TemplatesResourceWithRawResponse: + def __init__(self, templates: TemplatesResource) -> None: + self._templates = templates + + self.create = to_raw_response_wrapper( + templates.create, + ) + self.list = to_raw_response_wrapper( + templates.list, + ) + self.delete = to_raw_response_wrapper( + templates.delete, + ) + self.get = to_raw_response_wrapper( + templates.get, + ) + self.replace = to_raw_response_wrapper( + templates.replace, + ) + + +class AsyncTemplatesResourceWithRawResponse: + def __init__(self, templates: AsyncTemplatesResource) -> None: + self._templates = templates + + self.create = async_to_raw_response_wrapper( + templates.create, + ) + self.list = async_to_raw_response_wrapper( + templates.list, + ) + self.delete = async_to_raw_response_wrapper( + templates.delete, + ) + self.get = async_to_raw_response_wrapper( + templates.get, + ) + self.replace = async_to_raw_response_wrapper( + templates.replace, + ) + + +class TemplatesResourceWithStreamingResponse: + def __init__(self, templates: TemplatesResource) -> None: + self._templates = templates + + self.create = to_streamed_response_wrapper( + templates.create, + ) + self.list = to_streamed_response_wrapper( + templates.list, + ) + self.delete = to_streamed_response_wrapper( + templates.delete, + ) + self.get = to_streamed_response_wrapper( + templates.get, + ) + self.replace = to_streamed_response_wrapper( + templates.replace, + ) + + +class AsyncTemplatesResourceWithStreamingResponse: + def __init__(self, templates: AsyncTemplatesResource) -> None: + self._templates = templates + + self.create = async_to_streamed_response_wrapper( + templates.create, + ) + self.list = async_to_streamed_response_wrapper( + templates.list, + ) + self.delete = async_to_streamed_response_wrapper( + templates.delete, + ) + self.get = async_to_streamed_response_wrapper( + templates.get, + ) + self.replace = async_to_streamed_response_wrapper( + templates.replace, + ) diff --git a/src/gcore/resources/iam/__init__.py b/src/gcore/resources/iam/__init__.py new file mode 100644 index 00000000..e8a7c852 --- /dev/null +++ b/src/gcore/resources/iam/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .iam import ( + IamResource, + AsyncIamResource, + IamResourceWithRawResponse, + AsyncIamResourceWithRawResponse, + IamResourceWithStreamingResponse, + AsyncIamResourceWithStreamingResponse, +) +from .users import ( + UsersResource, + AsyncUsersResource, + UsersResourceWithRawResponse, + AsyncUsersResourceWithRawResponse, + UsersResourceWithStreamingResponse, + AsyncUsersResourceWithStreamingResponse, +) +from .api_tokens import ( + APITokensResource, + AsyncAPITokensResource, + APITokensResourceWithRawResponse, + AsyncAPITokensResourceWithRawResponse, + APITokensResourceWithStreamingResponse, + AsyncAPITokensResourceWithStreamingResponse, +) + +__all__ = [ + "APITokensResource", + "AsyncAPITokensResource", + "APITokensResourceWithRawResponse", + "AsyncAPITokensResourceWithRawResponse", + "APITokensResourceWithStreamingResponse", + "AsyncAPITokensResourceWithStreamingResponse", + "UsersResource", + "AsyncUsersResource", + "UsersResourceWithRawResponse", + "AsyncUsersResourceWithRawResponse", + "UsersResourceWithStreamingResponse", + "AsyncUsersResourceWithStreamingResponse", + "IamResource", + "AsyncIamResource", + "IamResourceWithRawResponse", + "AsyncIamResourceWithRawResponse", + "IamResourceWithStreamingResponse", + "AsyncIamResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/iam/api.md b/src/gcore/resources/iam/api.md new file mode 100644 index 00000000..b6411972 --- /dev/null +++ b/src/gcore/resources/iam/api.md @@ -0,0 +1,42 @@ +# Iam + +Types: + +```python +from gcore.types.iam import AccountOverview +``` + +Methods: + +- client.iam.get_account_overview() -> AccountOverview + +## APITokens + +Types: + +```python +from gcore.types.iam import APIToken, APITokenCreated, APITokenList +``` + +Methods: + +- client.iam.api_tokens.create(client_id, \*\*params) -> APITokenCreated +- client.iam.api_tokens.list(client_id, \*\*params) -> APITokenList +- client.iam.api_tokens.delete(token_id, \*, client_id) -> None +- client.iam.api_tokens.get(token_id, \*, client_id) -> APIToken + +## Users + +Types: + +```python +from gcore.types.iam import User, UserDetailed, UserInvite, UserUpdated +``` + +Methods: + +- client.iam.users.update(user_id, \*\*params) -> UserUpdated +- client.iam.users.list(\*\*params) -> SyncOffsetPage[User] +- client.iam.users.delete(user_id, \*, client_id) -> None +- client.iam.users.get(user_id) -> UserDetailed +- client.iam.users.invite(\*\*params) -> UserInvite diff --git a/src/gcore/resources/iam/api_tokens.py b/src/gcore/resources/iam/api_tokens.py new file mode 100644 index 00000000..6395270b --- /dev/null +++ b/src/gcore/resources/iam/api_tokens.py @@ -0,0 +1,523 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.iam import api_token_list_params, api_token_create_params +from ..._base_client import make_request_options +from ...types.iam.api_token import APIToken +from ...types.iam.api_token_list import APITokenList +from ...types.iam.api_token_created import APITokenCreated + +__all__ = ["APITokensResource", "AsyncAPITokensResource"] + + +class APITokensResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> APITokensResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return APITokensResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> APITokensResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return APITokensResourceWithStreamingResponse(self) + + def create( + self, + client_id: int, + *, + client_user: api_token_create_params.ClientUser, + exp_date: Optional[str], + name: str, + description: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> APITokenCreated: + """ + Create an API token in the current account. + + Args: + client_user: API token role. + + exp_date: Date when the API token becomes expired (ISO 8086/RFC 3339 format), UTC. If + null, then the API token will never expire. + + name: API token name. + + description: API token description. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/iam/clients/{client_id}/tokens", + body=maybe_transform( + { + "client_user": client_user, + "exp_date": exp_date, + "name": name, + "description": description, + }, + api_token_create_params.APITokenCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=APITokenCreated, + ) + + def list( + self, + client_id: int, + *, + deleted: bool | Omit = omit, + issued_by: int | Omit = omit, + not_issued_by: int | Omit = omit, + role: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> APITokenList: + """Get information about your permanent API tokens in the account. + + A user with the + Administrators role gets information about all API tokens in the account. + + Args: + deleted: The state of API tokens included in the response. + Two possible values: + + - True - API token was not deleted.\\** False - API token was deleted. + + Example, _&deleted=True_ + + issued_by: User's ID. Use to get API tokens issued by a particular user. + Example, _&`issued_by`=1234_ + + not_issued_by: User's ID. Use to get API tokens issued by anyone except a particular user. + Example, _¬_issued_by=1234_ + + role: + Group's ID. Possible values are: + + - 1 - Administrators* 2 - Users* 5 - Engineers* 3009 - Purge and Prefetch only + (API+Web)* 3022 - Purge and Prefetch only (API) + + Example, _&role=Engineers_ + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/iam/clients/{client_id}/tokens", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "deleted": deleted, + "issued_by": issued_by, + "not_issued_by": not_issued_by, + "role": role, + }, + api_token_list_params.APITokenListParams, + ), + ), + cast_to=APITokenList, + ) + + def delete( + self, + token_id: int, + *, + client_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete API token from current account. + + Ensure that the API token is not being + used by an active application. After deleting the token, all applications that + use this token will not be able to get access to your account via API. The + action cannot be reversed. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/iam/clients/{client_id}/tokens/{token_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + token_id: int, + *, + client_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> APIToken: + """ + Get API Token + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/iam/clients/{client_id}/tokens/{token_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=APIToken, + ) + + +class AsyncAPITokensResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAPITokensResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncAPITokensResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAPITokensResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncAPITokensResourceWithStreamingResponse(self) + + async def create( + self, + client_id: int, + *, + client_user: api_token_create_params.ClientUser, + exp_date: Optional[str], + name: str, + description: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> APITokenCreated: + """ + Create an API token in the current account. + + Args: + client_user: API token role. + + exp_date: Date when the API token becomes expired (ISO 8086/RFC 3339 format), UTC. If + null, then the API token will never expire. + + name: API token name. + + description: API token description. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/iam/clients/{client_id}/tokens", + body=await async_maybe_transform( + { + "client_user": client_user, + "exp_date": exp_date, + "name": name, + "description": description, + }, + api_token_create_params.APITokenCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=APITokenCreated, + ) + + async def list( + self, + client_id: int, + *, + deleted: bool | Omit = omit, + issued_by: int | Omit = omit, + not_issued_by: int | Omit = omit, + role: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> APITokenList: + """Get information about your permanent API tokens in the account. + + A user with the + Administrators role gets information about all API tokens in the account. + + Args: + deleted: The state of API tokens included in the response. + Two possible values: + + - True - API token was not deleted.\\** False - API token was deleted. + + Example, _&deleted=True_ + + issued_by: User's ID. Use to get API tokens issued by a particular user. + Example, _&`issued_by`=1234_ + + not_issued_by: User's ID. Use to get API tokens issued by anyone except a particular user. + Example, _¬_issued_by=1234_ + + role: + Group's ID. Possible values are: + + - 1 - Administrators* 2 - Users* 5 - Engineers* 3009 - Purge and Prefetch only + (API+Web)* 3022 - Purge and Prefetch only (API) + + Example, _&role=Engineers_ + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/iam/clients/{client_id}/tokens", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "deleted": deleted, + "issued_by": issued_by, + "not_issued_by": not_issued_by, + "role": role, + }, + api_token_list_params.APITokenListParams, + ), + ), + cast_to=APITokenList, + ) + + async def delete( + self, + token_id: int, + *, + client_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete API token from current account. + + Ensure that the API token is not being + used by an active application. After deleting the token, all applications that + use this token will not be able to get access to your account via API. The + action cannot be reversed. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/iam/clients/{client_id}/tokens/{token_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + token_id: int, + *, + client_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> APIToken: + """ + Get API Token + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/iam/clients/{client_id}/tokens/{token_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=APIToken, + ) + + +class APITokensResourceWithRawResponse: + def __init__(self, api_tokens: APITokensResource) -> None: + self._api_tokens = api_tokens + + self.create = to_raw_response_wrapper( + api_tokens.create, + ) + self.list = to_raw_response_wrapper( + api_tokens.list, + ) + self.delete = to_raw_response_wrapper( + api_tokens.delete, + ) + self.get = to_raw_response_wrapper( + api_tokens.get, + ) + + +class AsyncAPITokensResourceWithRawResponse: + def __init__(self, api_tokens: AsyncAPITokensResource) -> None: + self._api_tokens = api_tokens + + self.create = async_to_raw_response_wrapper( + api_tokens.create, + ) + self.list = async_to_raw_response_wrapper( + api_tokens.list, + ) + self.delete = async_to_raw_response_wrapper( + api_tokens.delete, + ) + self.get = async_to_raw_response_wrapper( + api_tokens.get, + ) + + +class APITokensResourceWithStreamingResponse: + def __init__(self, api_tokens: APITokensResource) -> None: + self._api_tokens = api_tokens + + self.create = to_streamed_response_wrapper( + api_tokens.create, + ) + self.list = to_streamed_response_wrapper( + api_tokens.list, + ) + self.delete = to_streamed_response_wrapper( + api_tokens.delete, + ) + self.get = to_streamed_response_wrapper( + api_tokens.get, + ) + + +class AsyncAPITokensResourceWithStreamingResponse: + def __init__(self, api_tokens: AsyncAPITokensResource) -> None: + self._api_tokens = api_tokens + + self.create = async_to_streamed_response_wrapper( + api_tokens.create, + ) + self.list = async_to_streamed_response_wrapper( + api_tokens.list, + ) + self.delete = async_to_streamed_response_wrapper( + api_tokens.delete, + ) + self.get = async_to_streamed_response_wrapper( + api_tokens.get, + ) diff --git a/src/gcore/resources/iam/iam.py b/src/gcore/resources/iam/iam.py new file mode 100644 index 00000000..7f409c61 --- /dev/null +++ b/src/gcore/resources/iam/iam.py @@ -0,0 +1,199 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .users import ( + UsersResource, + AsyncUsersResource, + UsersResourceWithRawResponse, + AsyncUsersResourceWithRawResponse, + UsersResourceWithStreamingResponse, + AsyncUsersResourceWithStreamingResponse, +) +from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._compat import cached_property +from .api_tokens import ( + APITokensResource, + AsyncAPITokensResource, + APITokensResourceWithRawResponse, + AsyncAPITokensResourceWithRawResponse, + APITokensResourceWithStreamingResponse, + AsyncAPITokensResourceWithStreamingResponse, +) +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.iam.account_overview import AccountOverview + +__all__ = ["IamResource", "AsyncIamResource"] + + +class IamResource(SyncAPIResource): + @cached_property + def api_tokens(self) -> APITokensResource: + return APITokensResource(self._client) + + @cached_property + def users(self) -> UsersResource: + return UsersResource(self._client) + + @cached_property + def with_raw_response(self) -> IamResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return IamResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> IamResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return IamResourceWithStreamingResponse(self) + + def get_account_overview( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AccountOverview: + """Get information about your profile, users and other account details.""" + return self._get( + "/iam/clients/me", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AccountOverview, + ) + + +class AsyncIamResource(AsyncAPIResource): + @cached_property + def api_tokens(self) -> AsyncAPITokensResource: + return AsyncAPITokensResource(self._client) + + @cached_property + def users(self) -> AsyncUsersResource: + return AsyncUsersResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncIamResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncIamResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncIamResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncIamResourceWithStreamingResponse(self) + + async def get_account_overview( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AccountOverview: + """Get information about your profile, users and other account details.""" + return await self._get( + "/iam/clients/me", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AccountOverview, + ) + + +class IamResourceWithRawResponse: + def __init__(self, iam: IamResource) -> None: + self._iam = iam + + self.get_account_overview = to_raw_response_wrapper( + iam.get_account_overview, + ) + + @cached_property + def api_tokens(self) -> APITokensResourceWithRawResponse: + return APITokensResourceWithRawResponse(self._iam.api_tokens) + + @cached_property + def users(self) -> UsersResourceWithRawResponse: + return UsersResourceWithRawResponse(self._iam.users) + + +class AsyncIamResourceWithRawResponse: + def __init__(self, iam: AsyncIamResource) -> None: + self._iam = iam + + self.get_account_overview = async_to_raw_response_wrapper( + iam.get_account_overview, + ) + + @cached_property + def api_tokens(self) -> AsyncAPITokensResourceWithRawResponse: + return AsyncAPITokensResourceWithRawResponse(self._iam.api_tokens) + + @cached_property + def users(self) -> AsyncUsersResourceWithRawResponse: + return AsyncUsersResourceWithRawResponse(self._iam.users) + + +class IamResourceWithStreamingResponse: + def __init__(self, iam: IamResource) -> None: + self._iam = iam + + self.get_account_overview = to_streamed_response_wrapper( + iam.get_account_overview, + ) + + @cached_property + def api_tokens(self) -> APITokensResourceWithStreamingResponse: + return APITokensResourceWithStreamingResponse(self._iam.api_tokens) + + @cached_property + def users(self) -> UsersResourceWithStreamingResponse: + return UsersResourceWithStreamingResponse(self._iam.users) + + +class AsyncIamResourceWithStreamingResponse: + def __init__(self, iam: AsyncIamResource) -> None: + self._iam = iam + + self.get_account_overview = async_to_streamed_response_wrapper( + iam.get_account_overview, + ) + + @cached_property + def api_tokens(self) -> AsyncAPITokensResourceWithStreamingResponse: + return AsyncAPITokensResourceWithStreamingResponse(self._iam.api_tokens) + + @cached_property + def users(self) -> AsyncUsersResourceWithStreamingResponse: + return AsyncUsersResourceWithStreamingResponse(self._iam.users) diff --git a/src/gcore/resources/iam/users.py b/src/gcore/resources/iam/users.py new file mode 100644 index 00000000..46d9a50c --- /dev/null +++ b/src/gcore/resources/iam/users.py @@ -0,0 +1,626 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.iam import user_list_params, user_invite_params, user_update_params +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.iam.user import User +from ...types.iam.user_invite import UserInvite +from ...types.iam.user_updated import UserUpdated +from ...types.iam.user_detailed import UserDetailed + +__all__ = ["UsersResource", "AsyncUsersResource"] + + +class UsersResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> UsersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return UsersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> UsersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return UsersResourceWithStreamingResponse(self) + + def update( + self, + user_id: int, + *, + auth_types: List[Literal["password", "sso", "github", "google-oauth2"]], + email: str, + lang: Literal["de", "en", "ru", "zh", "az"], + name: Optional[str], + phone: Optional[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserUpdated: + """This method updates user's details. + + Args: + auth_types: System field. + + List of auth types available for the account. + + email: User's email address. + + lang: User's language. + + Defines language of the control panel and email messages. + + name: User's name. + + phone: User's phone. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/iam/users/{user_id}", + body=maybe_transform( + { + "auth_types": auth_types, + "email": email, + "lang": lang, + "name": name, + "phone": phone, + }, + user_update_params.UserUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UserUpdated, + ) + + def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[User]: + """ + Get a list of users. + + Pass a value for the `limit` parameter in your request if you want retrieve a + paginated result. Otherwise API returns a list with all users without + pagination. + + Args: + limit: The maximum number of items. + + offset: Offset relative to the beginning of list. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/iam/users", + page=SyncOffsetPage[User], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + user_list_params.UserListParams, + ), + ), + model=User, + ) + + def delete( + self, + user_id: int, + *, + client_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Revokes user's access to the specified account. + + If the specified user doesn't + have access to multiple accounts, the user is deleted. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/iam/clients/{client_id}/client-users/{user_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + user_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserDetailed: + """ + Get user's details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/iam/users/{user_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UserDetailed, + ) + + def invite( + self, + *, + client_id: int, + email: str, + user_role: user_invite_params.UserRole, + lang: Literal["de", "en", "ru", "zh", "az"] | Omit = omit, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserInvite: + """Invite a user to the account. + + User will receive an email. + + The new user will receive an invitation email with a + link to create an account password, the existing user will be notified about the + invitation to the account. + + Args: + client_id: ID of account. + + email: User email. + + lang: User's language. + + Defines language of the control panel and email messages. + + name: User name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/iam/clients/invite_user", + body=maybe_transform( + { + "client_id": client_id, + "email": email, + "user_role": user_role, + "lang": lang, + "name": name, + }, + user_invite_params.UserInviteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UserInvite, + ) + + +class AsyncUsersResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncUsersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncUsersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncUsersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncUsersResourceWithStreamingResponse(self) + + async def update( + self, + user_id: int, + *, + auth_types: List[Literal["password", "sso", "github", "google-oauth2"]], + email: str, + lang: Literal["de", "en", "ru", "zh", "az"], + name: Optional[str], + phone: Optional[str], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserUpdated: + """This method updates user's details. + + Args: + auth_types: System field. + + List of auth types available for the account. + + email: User's email address. + + lang: User's language. + + Defines language of the control panel and email messages. + + name: User's name. + + phone: User's phone. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/iam/users/{user_id}", + body=await async_maybe_transform( + { + "auth_types": auth_types, + "email": email, + "lang": lang, + "name": name, + "phone": phone, + }, + user_update_params.UserUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UserUpdated, + ) + + def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[User, AsyncOffsetPage[User]]: + """ + Get a list of users. + + Pass a value for the `limit` parameter in your request if you want retrieve a + paginated result. Otherwise API returns a list with all users without + pagination. + + Args: + limit: The maximum number of items. + + offset: Offset relative to the beginning of list. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/iam/users", + page=AsyncOffsetPage[User], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + user_list_params.UserListParams, + ), + ), + model=User, + ) + + async def delete( + self, + user_id: int, + *, + client_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Revokes user's access to the specified account. + + If the specified user doesn't + have access to multiple accounts, the user is deleted. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/iam/clients/{client_id}/client-users/{user_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + user_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserDetailed: + """ + Get user's details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/iam/users/{user_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UserDetailed, + ) + + async def invite( + self, + *, + client_id: int, + email: str, + user_role: user_invite_params.UserRole, + lang: Literal["de", "en", "ru", "zh", "az"] | Omit = omit, + name: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UserInvite: + """Invite a user to the account. + + User will receive an email. + + The new user will receive an invitation email with a + link to create an account password, the existing user will be notified about the + invitation to the account. + + Args: + client_id: ID of account. + + email: User email. + + lang: User's language. + + Defines language of the control panel and email messages. + + name: User name. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/iam/clients/invite_user", + body=await async_maybe_transform( + { + "client_id": client_id, + "email": email, + "user_role": user_role, + "lang": lang, + "name": name, + }, + user_invite_params.UserInviteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UserInvite, + ) + + +class UsersResourceWithRawResponse: + def __init__(self, users: UsersResource) -> None: + self._users = users + + self.update = to_raw_response_wrapper( + users.update, + ) + self.list = to_raw_response_wrapper( + users.list, + ) + self.delete = to_raw_response_wrapper( + users.delete, + ) + self.get = to_raw_response_wrapper( + users.get, + ) + self.invite = to_raw_response_wrapper( + users.invite, + ) + + +class AsyncUsersResourceWithRawResponse: + def __init__(self, users: AsyncUsersResource) -> None: + self._users = users + + self.update = async_to_raw_response_wrapper( + users.update, + ) + self.list = async_to_raw_response_wrapper( + users.list, + ) + self.delete = async_to_raw_response_wrapper( + users.delete, + ) + self.get = async_to_raw_response_wrapper( + users.get, + ) + self.invite = async_to_raw_response_wrapper( + users.invite, + ) + + +class UsersResourceWithStreamingResponse: + def __init__(self, users: UsersResource) -> None: + self._users = users + + self.update = to_streamed_response_wrapper( + users.update, + ) + self.list = to_streamed_response_wrapper( + users.list, + ) + self.delete = to_streamed_response_wrapper( + users.delete, + ) + self.get = to_streamed_response_wrapper( + users.get, + ) + self.invite = to_streamed_response_wrapper( + users.invite, + ) + + +class AsyncUsersResourceWithStreamingResponse: + def __init__(self, users: AsyncUsersResource) -> None: + self._users = users + + self.update = async_to_streamed_response_wrapper( + users.update, + ) + self.list = async_to_streamed_response_wrapper( + users.list, + ) + self.delete = async_to_streamed_response_wrapper( + users.delete, + ) + self.get = async_to_streamed_response_wrapper( + users.get, + ) + self.invite = async_to_streamed_response_wrapper( + users.invite, + ) diff --git a/src/gcore/resources/security/__init__.py b/src/gcore/resources/security/__init__.py new file mode 100644 index 00000000..a1a7a5ea --- /dev/null +++ b/src/gcore/resources/security/__init__.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .events import ( + EventsResource, + AsyncEventsResource, + EventsResourceWithRawResponse, + AsyncEventsResourceWithRawResponse, + EventsResourceWithStreamingResponse, + AsyncEventsResourceWithStreamingResponse, +) +from .profiles import ( + ProfilesResource, + AsyncProfilesResource, + ProfilesResourceWithRawResponse, + AsyncProfilesResourceWithRawResponse, + ProfilesResourceWithStreamingResponse, + AsyncProfilesResourceWithStreamingResponse, +) +from .security import ( + SecurityResource, + AsyncSecurityResource, + SecurityResourceWithRawResponse, + AsyncSecurityResourceWithRawResponse, + SecurityResourceWithStreamingResponse, + AsyncSecurityResourceWithStreamingResponse, +) +from .bgp_announces import ( + BgpAnnouncesResource, + AsyncBgpAnnouncesResource, + BgpAnnouncesResourceWithRawResponse, + AsyncBgpAnnouncesResourceWithRawResponse, + BgpAnnouncesResourceWithStreamingResponse, + AsyncBgpAnnouncesResourceWithStreamingResponse, +) +from .profile_templates import ( + ProfileTemplatesResource, + AsyncProfileTemplatesResource, + ProfileTemplatesResourceWithRawResponse, + AsyncProfileTemplatesResourceWithRawResponse, + ProfileTemplatesResourceWithStreamingResponse, + AsyncProfileTemplatesResourceWithStreamingResponse, +) + +__all__ = [ + "EventsResource", + "AsyncEventsResource", + "EventsResourceWithRawResponse", + "AsyncEventsResourceWithRawResponse", + "EventsResourceWithStreamingResponse", + "AsyncEventsResourceWithStreamingResponse", + "BgpAnnouncesResource", + "AsyncBgpAnnouncesResource", + "BgpAnnouncesResourceWithRawResponse", + "AsyncBgpAnnouncesResourceWithRawResponse", + "BgpAnnouncesResourceWithStreamingResponse", + "AsyncBgpAnnouncesResourceWithStreamingResponse", + "ProfileTemplatesResource", + "AsyncProfileTemplatesResource", + "ProfileTemplatesResourceWithRawResponse", + "AsyncProfileTemplatesResourceWithRawResponse", + "ProfileTemplatesResourceWithStreamingResponse", + "AsyncProfileTemplatesResourceWithStreamingResponse", + "ProfilesResource", + "AsyncProfilesResource", + "ProfilesResourceWithRawResponse", + "AsyncProfilesResourceWithRawResponse", + "ProfilesResourceWithStreamingResponse", + "AsyncProfilesResourceWithStreamingResponse", + "SecurityResource", + "AsyncSecurityResource", + "SecurityResourceWithRawResponse", + "AsyncSecurityResourceWithRawResponse", + "SecurityResourceWithStreamingResponse", + "AsyncSecurityResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/security/api.md b/src/gcore/resources/security/api.md new file mode 100644 index 00000000..228f9548 --- /dev/null +++ b/src/gcore/resources/security/api.md @@ -0,0 +1,55 @@ +# Security + +## Events + +Types: + +```python +from gcore.types.security import ClientView +``` + +Methods: + +- client.security.events.list(\*\*params) -> SyncOffsetPage[ClientView] + +## BgpAnnounces + +Types: + +```python +from gcore.types.security import ClientAnnounce, BgpAnnounceListResponse +``` + +Methods: + +- client.security.bgp_announces.list(\*\*params) -> BgpAnnounceListResponse +- client.security.bgp_announces.toggle(\*\*params) -> object + +## ProfileTemplates + +Types: + +```python +from gcore.types.security import ClientProfileTemplate, ProfileTemplateListResponse +``` + +Methods: + +- client.security.profile_templates.list() -> ProfileTemplateListResponse + +## Profiles + +Types: + +```python +from gcore.types.security import ClientProfile, ProfileListResponse +``` + +Methods: + +- client.security.profiles.create(\*\*params) -> ClientProfile +- client.security.profiles.list(\*\*params) -> ProfileListResponse +- client.security.profiles.delete(id) -> None +- client.security.profiles.get(id) -> ClientProfile +- client.security.profiles.recreate(id, \*\*params) -> ClientProfile +- client.security.profiles.replace(id, \*\*params) -> ClientProfile diff --git a/src/gcore/resources/security/bgp_announces.py b/src/gcore/resources/security/bgp_announces.py new file mode 100644 index 00000000..1908f05a --- /dev/null +++ b/src/gcore/resources/security/bgp_announces.py @@ -0,0 +1,304 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.security import bgp_announce_list_params, bgp_announce_toggle_params +from ...types.security.bgp_announce_list_response import BgpAnnounceListResponse + +__all__ = ["BgpAnnouncesResource", "AsyncBgpAnnouncesResource"] + + +class BgpAnnouncesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> BgpAnnouncesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return BgpAnnouncesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BgpAnnouncesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return BgpAnnouncesResourceWithStreamingResponse(self) + + def list( + self, + *, + announced: Optional[bool] | Omit = omit, + origin: Optional[Literal["STATIC", "DYNAMIC"]] | Omit = omit, + site: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BgpAnnounceListResponse: + """Get BGP announces filtered by parameters. + + Shows announces in active profiles, + meaning that to get a non-empty response, the client must have at least one + active profile. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/security/sifter/v2/protected_addresses/announces", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "announced": announced, + "origin": origin, + "site": site, + }, + bgp_announce_list_params.BgpAnnounceListParams, + ), + ), + cast_to=BgpAnnounceListResponse, + ) + + def toggle( + self, + *, + announce: str, + enabled: bool, + client_id: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """Change BGP announces (it can be enabled or disabled, but not created or + updated). + + Can be applied to already existing announces in active profiles, + meaning that the client must have at least one active profile. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/security/sifter/v2/protected_addresses/announces", + body=maybe_transform( + { + "announce": announce, + "enabled": enabled, + }, + bgp_announce_toggle_params.BgpAnnounceToggleParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"client_id": client_id}, bgp_announce_toggle_params.BgpAnnounceToggleParams), + ), + cast_to=object, + ) + + +class AsyncBgpAnnouncesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncBgpAnnouncesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncBgpAnnouncesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBgpAnnouncesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncBgpAnnouncesResourceWithStreamingResponse(self) + + async def list( + self, + *, + announced: Optional[bool] | Omit = omit, + origin: Optional[Literal["STATIC", "DYNAMIC"]] | Omit = omit, + site: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BgpAnnounceListResponse: + """Get BGP announces filtered by parameters. + + Shows announces in active profiles, + meaning that to get a non-empty response, the client must have at least one + active profile. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/security/sifter/v2/protected_addresses/announces", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "announced": announced, + "origin": origin, + "site": site, + }, + bgp_announce_list_params.BgpAnnounceListParams, + ), + ), + cast_to=BgpAnnounceListResponse, + ) + + async def toggle( + self, + *, + announce: str, + enabled: bool, + client_id: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: + """Change BGP announces (it can be enabled or disabled, but not created or + updated). + + Can be applied to already existing announces in active profiles, + meaning that the client must have at least one active profile. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/security/sifter/v2/protected_addresses/announces", + body=await async_maybe_transform( + { + "announce": announce, + "enabled": enabled, + }, + bgp_announce_toggle_params.BgpAnnounceToggleParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"client_id": client_id}, bgp_announce_toggle_params.BgpAnnounceToggleParams + ), + ), + cast_to=object, + ) + + +class BgpAnnouncesResourceWithRawResponse: + def __init__(self, bgp_announces: BgpAnnouncesResource) -> None: + self._bgp_announces = bgp_announces + + self.list = to_raw_response_wrapper( + bgp_announces.list, + ) + self.toggle = to_raw_response_wrapper( + bgp_announces.toggle, + ) + + +class AsyncBgpAnnouncesResourceWithRawResponse: + def __init__(self, bgp_announces: AsyncBgpAnnouncesResource) -> None: + self._bgp_announces = bgp_announces + + self.list = async_to_raw_response_wrapper( + bgp_announces.list, + ) + self.toggle = async_to_raw_response_wrapper( + bgp_announces.toggle, + ) + + +class BgpAnnouncesResourceWithStreamingResponse: + def __init__(self, bgp_announces: BgpAnnouncesResource) -> None: + self._bgp_announces = bgp_announces + + self.list = to_streamed_response_wrapper( + bgp_announces.list, + ) + self.toggle = to_streamed_response_wrapper( + bgp_announces.toggle, + ) + + +class AsyncBgpAnnouncesResourceWithStreamingResponse: + def __init__(self, bgp_announces: AsyncBgpAnnouncesResource) -> None: + self._bgp_announces = bgp_announces + + self.list = async_to_streamed_response_wrapper( + bgp_announces.list, + ) + self.toggle = async_to_streamed_response_wrapper( + bgp_announces.toggle, + ) diff --git a/src/gcore/resources/security/events.py b/src/gcore/resources/security/events.py new file mode 100644 index 00000000..e0699398 --- /dev/null +++ b/src/gcore/resources/security/events.py @@ -0,0 +1,234 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.security import event_list_params +from ...types.security.client_view import ClientView + +__all__ = ["EventsResource", "AsyncEventsResource"] + + +class EventsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> EventsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return EventsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> EventsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return EventsResourceWithStreamingResponse(self) + + def list( + self, + *, + alert_type: Optional[Literal["ddos_alert", "rtbh_alert"]] | Omit = omit, + date_from: Union[Union[str, datetime], str] | Omit = omit, + date_to: Union[Union[str, datetime], str] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + ordering: Literal[ + "attack_start_time", + "-attack_start_time", + "attack_power_bps", + "-attack_power_bps", + "attack_power_pps", + "-attack_power_pps", + "number_of_ip_involved_in_attack", + "-number_of_ip_involved_in_attack", + "alert_type", + "-alert_type", + ] + | Omit = omit, + targeted_ip_addresses: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[ClientView]: + """ + Event Logs Clients View + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/security/notifier/v1/event_logs", + page=SyncOffsetPage[ClientView], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "alert_type": alert_type, + "date_from": date_from, + "date_to": date_to, + "limit": limit, + "offset": offset, + "ordering": ordering, + "targeted_ip_addresses": targeted_ip_addresses, + }, + event_list_params.EventListParams, + ), + ), + model=ClientView, + ) + + +class AsyncEventsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncEventsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncEventsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncEventsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncEventsResourceWithStreamingResponse(self) + + def list( + self, + *, + alert_type: Optional[Literal["ddos_alert", "rtbh_alert"]] | Omit = omit, + date_from: Union[Union[str, datetime], str] | Omit = omit, + date_to: Union[Union[str, datetime], str] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + ordering: Literal[ + "attack_start_time", + "-attack_start_time", + "attack_power_bps", + "-attack_power_bps", + "attack_power_pps", + "-attack_power_pps", + "number_of_ip_involved_in_attack", + "-number_of_ip_involved_in_attack", + "alert_type", + "-alert_type", + ] + | Omit = omit, + targeted_ip_addresses: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[ClientView, AsyncOffsetPage[ClientView]]: + """ + Event Logs Clients View + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/security/notifier/v1/event_logs", + page=AsyncOffsetPage[ClientView], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "alert_type": alert_type, + "date_from": date_from, + "date_to": date_to, + "limit": limit, + "offset": offset, + "ordering": ordering, + "targeted_ip_addresses": targeted_ip_addresses, + }, + event_list_params.EventListParams, + ), + ), + model=ClientView, + ) + + +class EventsResourceWithRawResponse: + def __init__(self, events: EventsResource) -> None: + self._events = events + + self.list = to_raw_response_wrapper( + events.list, + ) + + +class AsyncEventsResourceWithRawResponse: + def __init__(self, events: AsyncEventsResource) -> None: + self._events = events + + self.list = async_to_raw_response_wrapper( + events.list, + ) + + +class EventsResourceWithStreamingResponse: + def __init__(self, events: EventsResource) -> None: + self._events = events + + self.list = to_streamed_response_wrapper( + events.list, + ) + + +class AsyncEventsResourceWithStreamingResponse: + def __init__(self, events: AsyncEventsResource) -> None: + self._events = events + + self.list = async_to_streamed_response_wrapper( + events.list, + ) diff --git a/src/gcore/resources/security/profile_templates.py b/src/gcore/resources/security/profile_templates.py new file mode 100644 index 00000000..307f3c0d --- /dev/null +++ b/src/gcore/resources/security/profile_templates.py @@ -0,0 +1,143 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.security.profile_template_list_response import ProfileTemplateListResponse + +__all__ = ["ProfileTemplatesResource", "AsyncProfileTemplatesResource"] + + +class ProfileTemplatesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ProfileTemplatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ProfileTemplatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ProfileTemplatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ProfileTemplatesResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProfileTemplateListResponse: + """Get list of profile templates. + + Profile template is used as a template to create + profile. Client receives only common and created for him profile templates. + """ + return self._get( + "/security/iaas/profile-templates", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProfileTemplateListResponse, + ) + + +class AsyncProfileTemplatesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncProfileTemplatesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncProfileTemplatesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncProfileTemplatesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncProfileTemplatesResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProfileTemplateListResponse: + """Get list of profile templates. + + Profile template is used as a template to create + profile. Client receives only common and created for him profile templates. + """ + return await self._get( + "/security/iaas/profile-templates", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProfileTemplateListResponse, + ) + + +class ProfileTemplatesResourceWithRawResponse: + def __init__(self, profile_templates: ProfileTemplatesResource) -> None: + self._profile_templates = profile_templates + + self.list = to_raw_response_wrapper( + profile_templates.list, + ) + + +class AsyncProfileTemplatesResourceWithRawResponse: + def __init__(self, profile_templates: AsyncProfileTemplatesResource) -> None: + self._profile_templates = profile_templates + + self.list = async_to_raw_response_wrapper( + profile_templates.list, + ) + + +class ProfileTemplatesResourceWithStreamingResponse: + def __init__(self, profile_templates: ProfileTemplatesResource) -> None: + self._profile_templates = profile_templates + + self.list = to_streamed_response_wrapper( + profile_templates.list, + ) + + +class AsyncProfileTemplatesResourceWithStreamingResponse: + def __init__(self, profile_templates: AsyncProfileTemplatesResource) -> None: + self._profile_templates = profile_templates + + self.list = async_to_streamed_response_wrapper( + profile_templates.list, + ) diff --git a/src/gcore/resources/security/profiles.py b/src/gcore/resources/security/profiles.py new file mode 100644 index 00000000..13cfdcfa --- /dev/null +++ b/src/gcore/resources/security/profiles.py @@ -0,0 +1,685 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.security import ( + profile_list_params, + profile_create_params, + profile_replace_params, + profile_recreate_params, +) +from ...types.security.client_profile import ClientProfile +from ...types.security.profile_list_response import ProfileListResponse + +__all__ = ["ProfilesResource", "AsyncProfilesResource"] + + +class ProfilesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ProfilesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return ProfilesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ProfilesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return ProfilesResourceWithStreamingResponse(self) + + def create( + self, + *, + fields: Iterable[profile_create_params.Field], + profile_template: int, + site: str, + ip_address: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ClientProfile: + """Create protection profile. + + Protection is enabled at the same time as profile is + created + + Args: + site: Region where the protection profiles will be deployed + + ip_address: Required for Universal template only. Optional for all others. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/security/iaas/v2/profiles", + body=maybe_transform( + { + "fields": fields, + "profile_template": profile_template, + "site": site, + "ip_address": ip_address, + }, + profile_create_params.ProfileCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClientProfile, + ) + + def list( + self, + *, + exclude_empty_address: bool | Omit = omit, + include_deleted: bool | Omit = omit, + ip_address: str | Omit = omit, + site: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProfileListResponse: + """Get list of protection profiles. + + Client receives only profiles created by him + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/security/iaas/v2/profiles", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "exclude_empty_address": exclude_empty_address, + "include_deleted": include_deleted, + "ip_address": ip_address, + "site": site, + }, + profile_list_params.ProfileListParams, + ), + ), + cast_to=ProfileListResponse, + ) + + def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete protection profile. + + Protection is disabled at the same time as profile is + deleted + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/security/iaas/v2/profiles/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ClientProfile: + """ + Get profile by id + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/security/iaas/v2/profiles/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClientProfile, + ) + + def recreate( + self, + id: int, + *, + fields: Iterable[profile_recreate_params.Field], + profile_template: int, + ip_address: str | Omit = omit, + site: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ClientProfile: + """ + Recreate profile with another profile template (for other cases use detail API) + + Args: + ip_address: Required for Universal template only. Optional for all others. + + site: Region where the protection profiles will be deployed + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/security/iaas/v2/profiles/{id}/recreate", + body=maybe_transform( + { + "fields": fields, + "profile_template": profile_template, + "ip_address": ip_address, + "site": site, + }, + profile_recreate_params.ProfileRecreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClientProfile, + ) + + def replace( + self, + id: int, + *, + fields: Iterable[profile_replace_params.Field], + profile_template: int, + ip_address: str | Omit = omit, + site: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ClientProfile: + """Update profile. + + Protection policies are updated at the same time as profile + updated + + Args: + ip_address: Required for Universal template only. Optional for all others. + + site: Region where the protection profiles will be deployed + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/security/iaas/v2/profiles/{id}", + body=maybe_transform( + { + "fields": fields, + "profile_template": profile_template, + "ip_address": ip_address, + "site": site, + }, + profile_replace_params.ProfileReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClientProfile, + ) + + +class AsyncProfilesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncProfilesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncProfilesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncProfilesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncProfilesResourceWithStreamingResponse(self) + + async def create( + self, + *, + fields: Iterable[profile_create_params.Field], + profile_template: int, + site: str, + ip_address: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ClientProfile: + """Create protection profile. + + Protection is enabled at the same time as profile is + created + + Args: + site: Region where the protection profiles will be deployed + + ip_address: Required for Universal template only. Optional for all others. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/security/iaas/v2/profiles", + body=await async_maybe_transform( + { + "fields": fields, + "profile_template": profile_template, + "site": site, + "ip_address": ip_address, + }, + profile_create_params.ProfileCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClientProfile, + ) + + async def list( + self, + *, + exclude_empty_address: bool | Omit = omit, + include_deleted: bool | Omit = omit, + ip_address: str | Omit = omit, + site: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProfileListResponse: + """Get list of protection profiles. + + Client receives only profiles created by him + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/security/iaas/v2/profiles", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "exclude_empty_address": exclude_empty_address, + "include_deleted": include_deleted, + "ip_address": ip_address, + "site": site, + }, + profile_list_params.ProfileListParams, + ), + ), + cast_to=ProfileListResponse, + ) + + async def delete( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete protection profile. + + Protection is disabled at the same time as profile is + deleted + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/security/iaas/v2/profiles/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ClientProfile: + """ + Get profile by id + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/security/iaas/v2/profiles/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClientProfile, + ) + + async def recreate( + self, + id: int, + *, + fields: Iterable[profile_recreate_params.Field], + profile_template: int, + ip_address: str | Omit = omit, + site: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ClientProfile: + """ + Recreate profile with another profile template (for other cases use detail API) + + Args: + ip_address: Required for Universal template only. Optional for all others. + + site: Region where the protection profiles will be deployed + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/security/iaas/v2/profiles/{id}/recreate", + body=await async_maybe_transform( + { + "fields": fields, + "profile_template": profile_template, + "ip_address": ip_address, + "site": site, + }, + profile_recreate_params.ProfileRecreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClientProfile, + ) + + async def replace( + self, + id: int, + *, + fields: Iterable[profile_replace_params.Field], + profile_template: int, + ip_address: str | Omit = omit, + site: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ClientProfile: + """Update profile. + + Protection policies are updated at the same time as profile + updated + + Args: + ip_address: Required for Universal template only. Optional for all others. + + site: Region where the protection profiles will be deployed + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/security/iaas/v2/profiles/{id}", + body=await async_maybe_transform( + { + "fields": fields, + "profile_template": profile_template, + "ip_address": ip_address, + "site": site, + }, + profile_replace_params.ProfileReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClientProfile, + ) + + +class ProfilesResourceWithRawResponse: + def __init__(self, profiles: ProfilesResource) -> None: + self._profiles = profiles + + self.create = to_raw_response_wrapper( + profiles.create, + ) + self.list = to_raw_response_wrapper( + profiles.list, + ) + self.delete = to_raw_response_wrapper( + profiles.delete, + ) + self.get = to_raw_response_wrapper( + profiles.get, + ) + self.recreate = to_raw_response_wrapper( + profiles.recreate, + ) + self.replace = to_raw_response_wrapper( + profiles.replace, + ) + + +class AsyncProfilesResourceWithRawResponse: + def __init__(self, profiles: AsyncProfilesResource) -> None: + self._profiles = profiles + + self.create = async_to_raw_response_wrapper( + profiles.create, + ) + self.list = async_to_raw_response_wrapper( + profiles.list, + ) + self.delete = async_to_raw_response_wrapper( + profiles.delete, + ) + self.get = async_to_raw_response_wrapper( + profiles.get, + ) + self.recreate = async_to_raw_response_wrapper( + profiles.recreate, + ) + self.replace = async_to_raw_response_wrapper( + profiles.replace, + ) + + +class ProfilesResourceWithStreamingResponse: + def __init__(self, profiles: ProfilesResource) -> None: + self._profiles = profiles + + self.create = to_streamed_response_wrapper( + profiles.create, + ) + self.list = to_streamed_response_wrapper( + profiles.list, + ) + self.delete = to_streamed_response_wrapper( + profiles.delete, + ) + self.get = to_streamed_response_wrapper( + profiles.get, + ) + self.recreate = to_streamed_response_wrapper( + profiles.recreate, + ) + self.replace = to_streamed_response_wrapper( + profiles.replace, + ) + + +class AsyncProfilesResourceWithStreamingResponse: + def __init__(self, profiles: AsyncProfilesResource) -> None: + self._profiles = profiles + + self.create = async_to_streamed_response_wrapper( + profiles.create, + ) + self.list = async_to_streamed_response_wrapper( + profiles.list, + ) + self.delete = async_to_streamed_response_wrapper( + profiles.delete, + ) + self.get = async_to_streamed_response_wrapper( + profiles.get, + ) + self.recreate = async_to_streamed_response_wrapper( + profiles.recreate, + ) + self.replace = async_to_streamed_response_wrapper( + profiles.replace, + ) diff --git a/src/gcore/resources/security/security.py b/src/gcore/resources/security/security.py new file mode 100644 index 00000000..2d0d9c11 --- /dev/null +++ b/src/gcore/resources/security/security.py @@ -0,0 +1,198 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .events import ( + EventsResource, + AsyncEventsResource, + EventsResourceWithRawResponse, + AsyncEventsResourceWithRawResponse, + EventsResourceWithStreamingResponse, + AsyncEventsResourceWithStreamingResponse, +) +from .profiles import ( + ProfilesResource, + AsyncProfilesResource, + ProfilesResourceWithRawResponse, + AsyncProfilesResourceWithRawResponse, + ProfilesResourceWithStreamingResponse, + AsyncProfilesResourceWithStreamingResponse, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from .bgp_announces import ( + BgpAnnouncesResource, + AsyncBgpAnnouncesResource, + BgpAnnouncesResourceWithRawResponse, + AsyncBgpAnnouncesResourceWithRawResponse, + BgpAnnouncesResourceWithStreamingResponse, + AsyncBgpAnnouncesResourceWithStreamingResponse, +) +from .profile_templates import ( + ProfileTemplatesResource, + AsyncProfileTemplatesResource, + ProfileTemplatesResourceWithRawResponse, + AsyncProfileTemplatesResourceWithRawResponse, + ProfileTemplatesResourceWithStreamingResponse, + AsyncProfileTemplatesResourceWithStreamingResponse, +) + +__all__ = ["SecurityResource", "AsyncSecurityResource"] + + +class SecurityResource(SyncAPIResource): + @cached_property + def events(self) -> EventsResource: + return EventsResource(self._client) + + @cached_property + def bgp_announces(self) -> BgpAnnouncesResource: + return BgpAnnouncesResource(self._client) + + @cached_property + def profile_templates(self) -> ProfileTemplatesResource: + return ProfileTemplatesResource(self._client) + + @cached_property + def profiles(self) -> ProfilesResource: + return ProfilesResource(self._client) + + @cached_property + def with_raw_response(self) -> SecurityResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return SecurityResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SecurityResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return SecurityResourceWithStreamingResponse(self) + + +class AsyncSecurityResource(AsyncAPIResource): + @cached_property + def events(self) -> AsyncEventsResource: + return AsyncEventsResource(self._client) + + @cached_property + def bgp_announces(self) -> AsyncBgpAnnouncesResource: + return AsyncBgpAnnouncesResource(self._client) + + @cached_property + def profile_templates(self) -> AsyncProfileTemplatesResource: + return AsyncProfileTemplatesResource(self._client) + + @cached_property + def profiles(self) -> AsyncProfilesResource: + return AsyncProfilesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncSecurityResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncSecurityResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSecurityResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncSecurityResourceWithStreamingResponse(self) + + +class SecurityResourceWithRawResponse: + def __init__(self, security: SecurityResource) -> None: + self._security = security + + @cached_property + def events(self) -> EventsResourceWithRawResponse: + return EventsResourceWithRawResponse(self._security.events) + + @cached_property + def bgp_announces(self) -> BgpAnnouncesResourceWithRawResponse: + return BgpAnnouncesResourceWithRawResponse(self._security.bgp_announces) + + @cached_property + def profile_templates(self) -> ProfileTemplatesResourceWithRawResponse: + return ProfileTemplatesResourceWithRawResponse(self._security.profile_templates) + + @cached_property + def profiles(self) -> ProfilesResourceWithRawResponse: + return ProfilesResourceWithRawResponse(self._security.profiles) + + +class AsyncSecurityResourceWithRawResponse: + def __init__(self, security: AsyncSecurityResource) -> None: + self._security = security + + @cached_property + def events(self) -> AsyncEventsResourceWithRawResponse: + return AsyncEventsResourceWithRawResponse(self._security.events) + + @cached_property + def bgp_announces(self) -> AsyncBgpAnnouncesResourceWithRawResponse: + return AsyncBgpAnnouncesResourceWithRawResponse(self._security.bgp_announces) + + @cached_property + def profile_templates(self) -> AsyncProfileTemplatesResourceWithRawResponse: + return AsyncProfileTemplatesResourceWithRawResponse(self._security.profile_templates) + + @cached_property + def profiles(self) -> AsyncProfilesResourceWithRawResponse: + return AsyncProfilesResourceWithRawResponse(self._security.profiles) + + +class SecurityResourceWithStreamingResponse: + def __init__(self, security: SecurityResource) -> None: + self._security = security + + @cached_property + def events(self) -> EventsResourceWithStreamingResponse: + return EventsResourceWithStreamingResponse(self._security.events) + + @cached_property + def bgp_announces(self) -> BgpAnnouncesResourceWithStreamingResponse: + return BgpAnnouncesResourceWithStreamingResponse(self._security.bgp_announces) + + @cached_property + def profile_templates(self) -> ProfileTemplatesResourceWithStreamingResponse: + return ProfileTemplatesResourceWithStreamingResponse(self._security.profile_templates) + + @cached_property + def profiles(self) -> ProfilesResourceWithStreamingResponse: + return ProfilesResourceWithStreamingResponse(self._security.profiles) + + +class AsyncSecurityResourceWithStreamingResponse: + def __init__(self, security: AsyncSecurityResource) -> None: + self._security = security + + @cached_property + def events(self) -> AsyncEventsResourceWithStreamingResponse: + return AsyncEventsResourceWithStreamingResponse(self._security.events) + + @cached_property + def bgp_announces(self) -> AsyncBgpAnnouncesResourceWithStreamingResponse: + return AsyncBgpAnnouncesResourceWithStreamingResponse(self._security.bgp_announces) + + @cached_property + def profile_templates(self) -> AsyncProfileTemplatesResourceWithStreamingResponse: + return AsyncProfileTemplatesResourceWithStreamingResponse(self._security.profile_templates) + + @cached_property + def profiles(self) -> AsyncProfilesResourceWithStreamingResponse: + return AsyncProfilesResourceWithStreamingResponse(self._security.profiles) diff --git a/src/gcore/resources/storage/__init__.py b/src/gcore/resources/storage/__init__.py new file mode 100644 index 00000000..00eb3797 --- /dev/null +++ b/src/gcore/resources/storage/__init__.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .buckets import ( + BucketsResource, + AsyncBucketsResource, + BucketsResourceWithRawResponse, + AsyncBucketsResourceWithRawResponse, + BucketsResourceWithStreamingResponse, + AsyncBucketsResourceWithStreamingResponse, +) +from .storage import ( + StorageResource, + AsyncStorageResource, + StorageResourceWithRawResponse, + AsyncStorageResourceWithRawResponse, + StorageResourceWithStreamingResponse, + AsyncStorageResourceWithStreamingResponse, +) +from .locations import ( + LocationsResource, + AsyncLocationsResource, + LocationsResourceWithRawResponse, + AsyncLocationsResourceWithRawResponse, + LocationsResourceWithStreamingResponse, + AsyncLocationsResourceWithStreamingResponse, +) +from .statistics import ( + StatisticsResource, + AsyncStatisticsResource, + StatisticsResourceWithRawResponse, + AsyncStatisticsResourceWithRawResponse, + StatisticsResourceWithStreamingResponse, + AsyncStatisticsResourceWithStreamingResponse, +) +from .credentials import ( + CredentialsResource, + AsyncCredentialsResource, + CredentialsResourceWithRawResponse, + AsyncCredentialsResourceWithRawResponse, + CredentialsResourceWithStreamingResponse, + AsyncCredentialsResourceWithStreamingResponse, +) + +__all__ = [ + "LocationsResource", + "AsyncLocationsResource", + "LocationsResourceWithRawResponse", + "AsyncLocationsResourceWithRawResponse", + "LocationsResourceWithStreamingResponse", + "AsyncLocationsResourceWithStreamingResponse", + "StatisticsResource", + "AsyncStatisticsResource", + "StatisticsResourceWithRawResponse", + "AsyncStatisticsResourceWithRawResponse", + "StatisticsResourceWithStreamingResponse", + "AsyncStatisticsResourceWithStreamingResponse", + "CredentialsResource", + "AsyncCredentialsResource", + "CredentialsResourceWithRawResponse", + "AsyncCredentialsResourceWithRawResponse", + "CredentialsResourceWithStreamingResponse", + "AsyncCredentialsResourceWithStreamingResponse", + "BucketsResource", + "AsyncBucketsResource", + "BucketsResourceWithRawResponse", + "AsyncBucketsResourceWithRawResponse", + "BucketsResourceWithStreamingResponse", + "AsyncBucketsResourceWithStreamingResponse", + "StorageResource", + "AsyncStorageResource", + "StorageResourceWithRawResponse", + "AsyncStorageResourceWithRawResponse", + "StorageResourceWithStreamingResponse", + "AsyncStorageResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/storage/api.md b/src/gcore/resources/storage/api.md new file mode 100644 index 00000000..83eea9dc --- /dev/null +++ b/src/gcore/resources/storage/api.md @@ -0,0 +1,97 @@ +# Storage + +Types: + +```python +from gcore.types.storage import Storage +``` + +Methods: + +- client.storage.create(\*\*params) -> Storage +- client.storage.update(storage_id, \*\*params) -> Storage +- client.storage.list(\*\*params) -> SyncOffsetPage[Storage] +- client.storage.delete(storage_id) -> None +- client.storage.get(storage_id) -> Storage +- client.storage.link_ssh_key(key_id, \*, storage_id) -> None +- client.storage.restore(storage_id, \*\*params) -> None +- client.storage.unlink_ssh_key(key_id, \*, storage_id) -> None + +## Locations + +Types: + +```python +from gcore.types.storage import Location +``` + +Methods: + +- client.storage.locations.list(\*\*params) -> SyncOffsetPage[Location] + +## Statistics + +Types: + +```python +from gcore.types.storage import UsageSeries, UsageTotal, StatisticGetUsageSeriesResponse +``` + +Methods: + +- client.storage.statistics.get_usage_aggregated(\*\*params) -> UsageTotal +- client.storage.statistics.get_usage_series(\*\*params) -> StatisticGetUsageSeriesResponse + +## Credentials + +Methods: + +- client.storage.credentials.recreate(storage_id, \*\*params) -> Storage + +## Buckets + +Types: + +```python +from gcore.types.storage import Bucket +``` + +Methods: + +- client.storage.buckets.create(bucket_name, \*, storage_id) -> None +- client.storage.buckets.list(storage_id, \*\*params) -> SyncOffsetPage[Bucket] +- client.storage.buckets.delete(bucket_name, \*, storage_id) -> None + +### Cors + +Types: + +```python +from gcore.types.storage.buckets import BucketCors +``` + +Methods: + +- client.storage.buckets.cors.create(bucket_name, \*, storage_id, \*\*params) -> None +- client.storage.buckets.cors.get(bucket_name, \*, storage_id) -> BucketCors + +### Lifecycle + +Methods: + +- client.storage.buckets.lifecycle.create(bucket_name, \*, storage_id, \*\*params) -> None +- client.storage.buckets.lifecycle.delete(bucket_name, \*, storage_id) -> None + +### Policy + +Types: + +```python +from gcore.types.storage.buckets import BucketPolicy, PolicyGetResponse +``` + +Methods: + +- client.storage.buckets.policy.create(bucket_name, \*, storage_id) -> None +- client.storage.buckets.policy.delete(bucket_name, \*, storage_id) -> None +- client.storage.buckets.policy.get(bucket_name, \*, storage_id) -> PolicyGetResponse diff --git a/src/gcore/resources/storage/buckets/__init__.py b/src/gcore/resources/storage/buckets/__init__.py new file mode 100644 index 00000000..2ec8d4d5 --- /dev/null +++ b/src/gcore/resources/storage/buckets/__init__.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .cors import ( + CorsResource, + AsyncCorsResource, + CorsResourceWithRawResponse, + AsyncCorsResourceWithRawResponse, + CorsResourceWithStreamingResponse, + AsyncCorsResourceWithStreamingResponse, +) +from .policy import ( + PolicyResource, + AsyncPolicyResource, + PolicyResourceWithRawResponse, + AsyncPolicyResourceWithRawResponse, + PolicyResourceWithStreamingResponse, + AsyncPolicyResourceWithStreamingResponse, +) +from .buckets import ( + BucketsResource, + AsyncBucketsResource, + BucketsResourceWithRawResponse, + AsyncBucketsResourceWithRawResponse, + BucketsResourceWithStreamingResponse, + AsyncBucketsResourceWithStreamingResponse, +) +from .lifecycle import ( + LifecycleResource, + AsyncLifecycleResource, + LifecycleResourceWithRawResponse, + AsyncLifecycleResourceWithRawResponse, + LifecycleResourceWithStreamingResponse, + AsyncLifecycleResourceWithStreamingResponse, +) + +__all__ = [ + "CorsResource", + "AsyncCorsResource", + "CorsResourceWithRawResponse", + "AsyncCorsResourceWithRawResponse", + "CorsResourceWithStreamingResponse", + "AsyncCorsResourceWithStreamingResponse", + "LifecycleResource", + "AsyncLifecycleResource", + "LifecycleResourceWithRawResponse", + "AsyncLifecycleResourceWithRawResponse", + "LifecycleResourceWithStreamingResponse", + "AsyncLifecycleResourceWithStreamingResponse", + "PolicyResource", + "AsyncPolicyResource", + "PolicyResourceWithRawResponse", + "AsyncPolicyResourceWithRawResponse", + "PolicyResourceWithStreamingResponse", + "AsyncPolicyResourceWithStreamingResponse", + "BucketsResource", + "AsyncBucketsResource", + "BucketsResourceWithRawResponse", + "AsyncBucketsResourceWithRawResponse", + "BucketsResourceWithStreamingResponse", + "AsyncBucketsResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/storage/buckets/buckets.py b/src/gcore/resources/storage/buckets/buckets.py new file mode 100644 index 00000000..e6c589fa --- /dev/null +++ b/src/gcore/resources/storage/buckets/buckets.py @@ -0,0 +1,470 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .cors import ( + CorsResource, + AsyncCorsResource, + CorsResourceWithRawResponse, + AsyncCorsResourceWithRawResponse, + CorsResourceWithStreamingResponse, + AsyncCorsResourceWithStreamingResponse, +) +from .policy import ( + PolicyResource, + AsyncPolicyResource, + PolicyResourceWithRawResponse, + AsyncPolicyResourceWithRawResponse, + PolicyResourceWithStreamingResponse, + AsyncPolicyResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform +from .lifecycle import ( + LifecycleResource, + AsyncLifecycleResource, + LifecycleResourceWithRawResponse, + AsyncLifecycleResourceWithRawResponse, + LifecycleResourceWithStreamingResponse, + AsyncLifecycleResourceWithStreamingResponse, +) +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.storage import bucket_list_params +from ....types.storage.bucket import Bucket + +__all__ = ["BucketsResource", "AsyncBucketsResource"] + + +class BucketsResource(SyncAPIResource): + @cached_property + def cors(self) -> CorsResource: + return CorsResource(self._client) + + @cached_property + def lifecycle(self) -> LifecycleResource: + return LifecycleResource(self._client) + + @cached_property + def policy(self) -> PolicyResource: + return PolicyResource(self._client) + + @cached_property + def with_raw_response(self) -> BucketsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return BucketsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BucketsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return BucketsResourceWithStreamingResponse(self) + + def create( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Creates a new bucket within an S3 storage. + + Only applicable to S3-compatible + storages. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + storage_id: int, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[Bucket]: + """ + Returns the list of buckets for the storage in a wrapped response. + + Response format: count: total number of buckets (independent of pagination) + results: current page of buckets according to limit/offset + + Args: + limit: Max number of records in response + + offset: Number of records to skip before beginning to write in response. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/storage/provisioning/v2/storage/{storage_id}/s3/buckets", + page=SyncOffsetPage[Bucket], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + bucket_list_params.BucketListParams, + ), + ), + model=Bucket, + ) + + def delete( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Removes a bucket from an S3 storage. + + All objects in the bucket will be + automatically deleted before the bucket is removed. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncBucketsResource(AsyncAPIResource): + @cached_property + def cors(self) -> AsyncCorsResource: + return AsyncCorsResource(self._client) + + @cached_property + def lifecycle(self) -> AsyncLifecycleResource: + return AsyncLifecycleResource(self._client) + + @cached_property + def policy(self) -> AsyncPolicyResource: + return AsyncPolicyResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncBucketsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncBucketsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBucketsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncBucketsResourceWithStreamingResponse(self) + + async def create( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Creates a new bucket within an S3 storage. + + Only applicable to S3-compatible + storages. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + storage_id: int, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Bucket, AsyncOffsetPage[Bucket]]: + """ + Returns the list of buckets for the storage in a wrapped response. + + Response format: count: total number of buckets (independent of pagination) + results: current page of buckets according to limit/offset + + Args: + limit: Max number of records in response + + offset: Number of records to skip before beginning to write in response. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/storage/provisioning/v2/storage/{storage_id}/s3/buckets", + page=AsyncOffsetPage[Bucket], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + bucket_list_params.BucketListParams, + ), + ), + model=Bucket, + ) + + async def delete( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Removes a bucket from an S3 storage. + + All objects in the bucket will be + automatically deleted before the bucket is removed. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class BucketsResourceWithRawResponse: + def __init__(self, buckets: BucketsResource) -> None: + self._buckets = buckets + + self.create = to_raw_response_wrapper( + buckets.create, + ) + self.list = to_raw_response_wrapper( + buckets.list, + ) + self.delete = to_raw_response_wrapper( + buckets.delete, + ) + + @cached_property + def cors(self) -> CorsResourceWithRawResponse: + return CorsResourceWithRawResponse(self._buckets.cors) + + @cached_property + def lifecycle(self) -> LifecycleResourceWithRawResponse: + return LifecycleResourceWithRawResponse(self._buckets.lifecycle) + + @cached_property + def policy(self) -> PolicyResourceWithRawResponse: + return PolicyResourceWithRawResponse(self._buckets.policy) + + +class AsyncBucketsResourceWithRawResponse: + def __init__(self, buckets: AsyncBucketsResource) -> None: + self._buckets = buckets + + self.create = async_to_raw_response_wrapper( + buckets.create, + ) + self.list = async_to_raw_response_wrapper( + buckets.list, + ) + self.delete = async_to_raw_response_wrapper( + buckets.delete, + ) + + @cached_property + def cors(self) -> AsyncCorsResourceWithRawResponse: + return AsyncCorsResourceWithRawResponse(self._buckets.cors) + + @cached_property + def lifecycle(self) -> AsyncLifecycleResourceWithRawResponse: + return AsyncLifecycleResourceWithRawResponse(self._buckets.lifecycle) + + @cached_property + def policy(self) -> AsyncPolicyResourceWithRawResponse: + return AsyncPolicyResourceWithRawResponse(self._buckets.policy) + + +class BucketsResourceWithStreamingResponse: + def __init__(self, buckets: BucketsResource) -> None: + self._buckets = buckets + + self.create = to_streamed_response_wrapper( + buckets.create, + ) + self.list = to_streamed_response_wrapper( + buckets.list, + ) + self.delete = to_streamed_response_wrapper( + buckets.delete, + ) + + @cached_property + def cors(self) -> CorsResourceWithStreamingResponse: + return CorsResourceWithStreamingResponse(self._buckets.cors) + + @cached_property + def lifecycle(self) -> LifecycleResourceWithStreamingResponse: + return LifecycleResourceWithStreamingResponse(self._buckets.lifecycle) + + @cached_property + def policy(self) -> PolicyResourceWithStreamingResponse: + return PolicyResourceWithStreamingResponse(self._buckets.policy) + + +class AsyncBucketsResourceWithStreamingResponse: + def __init__(self, buckets: AsyncBucketsResource) -> None: + self._buckets = buckets + + self.create = async_to_streamed_response_wrapper( + buckets.create, + ) + self.list = async_to_streamed_response_wrapper( + buckets.list, + ) + self.delete = async_to_streamed_response_wrapper( + buckets.delete, + ) + + @cached_property + def cors(self) -> AsyncCorsResourceWithStreamingResponse: + return AsyncCorsResourceWithStreamingResponse(self._buckets.cors) + + @cached_property + def lifecycle(self) -> AsyncLifecycleResourceWithStreamingResponse: + return AsyncLifecycleResourceWithStreamingResponse(self._buckets.lifecycle) + + @cached_property + def policy(self) -> AsyncPolicyResourceWithStreamingResponse: + return AsyncPolicyResourceWithStreamingResponse(self._buckets.policy) diff --git a/src/gcore/resources/storage/buckets/cors.py b/src/gcore/resources/storage/buckets/cors.py new file mode 100644 index 00000000..77a3e045 --- /dev/null +++ b/src/gcore/resources/storage/buckets/cors.py @@ -0,0 +1,265 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.storage.buckets import cor_create_params +from ....types.storage.buckets.bucket_cors import BucketCors + +__all__ = ["CorsResource", "AsyncCorsResource"] + + +class CorsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return CorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return CorsResourceWithStreamingResponse(self) + + def create( + self, + bucket_name: str, + *, + storage_id: int, + allowed_origins: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Configures Cross-Origin Resource Sharing (CORS) rules for an S3 bucket, allowing + web applications from specified domains to access bucket resources directly from + browsers. + + Args: + allowed_origins: List of allowed origins for CORS requests + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/cors", + body=maybe_transform({"allowed_origins": allowed_origins}, cor_create_params.CorCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BucketCors: + """ + Retrieves the current Cross-Origin Resource Sharing (CORS) configuration for an + S3 bucket, showing which domains are allowed to access the bucket from web + browsers. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + return self._get( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/cors", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BucketCors, + ) + + +class AsyncCorsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCorsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncCorsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCorsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncCorsResourceWithStreamingResponse(self) + + async def create( + self, + bucket_name: str, + *, + storage_id: int, + allowed_origins: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Configures Cross-Origin Resource Sharing (CORS) rules for an S3 bucket, allowing + web applications from specified domains to access bucket resources directly from + browsers. + + Args: + allowed_origins: List of allowed origins for CORS requests + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/cors", + body=await async_maybe_transform({"allowed_origins": allowed_origins}, cor_create_params.CorCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BucketCors: + """ + Retrieves the current Cross-Origin Resource Sharing (CORS) configuration for an + S3 bucket, showing which domains are allowed to access the bucket from web + browsers. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + return await self._get( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/cors", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BucketCors, + ) + + +class CorsResourceWithRawResponse: + def __init__(self, cors: CorsResource) -> None: + self._cors = cors + + self.create = to_raw_response_wrapper( + cors.create, + ) + self.get = to_raw_response_wrapper( + cors.get, + ) + + +class AsyncCorsResourceWithRawResponse: + def __init__(self, cors: AsyncCorsResource) -> None: + self._cors = cors + + self.create = async_to_raw_response_wrapper( + cors.create, + ) + self.get = async_to_raw_response_wrapper( + cors.get, + ) + + +class CorsResourceWithStreamingResponse: + def __init__(self, cors: CorsResource) -> None: + self._cors = cors + + self.create = to_streamed_response_wrapper( + cors.create, + ) + self.get = to_streamed_response_wrapper( + cors.get, + ) + + +class AsyncCorsResourceWithStreamingResponse: + def __init__(self, cors: AsyncCorsResource) -> None: + self._cors = cors + + self.create = async_to_streamed_response_wrapper( + cors.create, + ) + self.get = async_to_streamed_response_wrapper( + cors.get, + ) diff --git a/src/gcore/resources/storage/buckets/lifecycle.py b/src/gcore/resources/storage/buckets/lifecycle.py new file mode 100644 index 00000000..b80dffaf --- /dev/null +++ b/src/gcore/resources/storage/buckets/lifecycle.py @@ -0,0 +1,276 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.storage.buckets import lifecycle_create_params + +__all__ = ["LifecycleResource", "AsyncLifecycleResource"] + + +class LifecycleResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> LifecycleResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return LifecycleResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> LifecycleResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return LifecycleResourceWithStreamingResponse(self) + + def create( + self, + bucket_name: str, + *, + storage_id: int, + expiration_days: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Sets up automatic object expiration for an S3 bucket. + + All objects in the bucket + will be automatically deleted after the specified number of days to help manage + storage costs and meet compliance requirements. This applies a global lifecycle + rule to the entire bucket - all existing and future objects will be subject to + the expiration policy. + + Args: + expiration_days: Number of days after which objects will be automatically deleted from the + bucket. Must be a positive integer. Common values: 30 for monthly cleanup, 365 + for yearly retention. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/lifecycle", + body=maybe_transform({"expiration_days": expiration_days}, lifecycle_create_params.LifecycleCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def delete( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Removes all lifecycle rules from an S3 bucket, disabling automatic object + expiration. Objects will no longer be automatically deleted based on age. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/lifecycle", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncLifecycleResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncLifecycleResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncLifecycleResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncLifecycleResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncLifecycleResourceWithStreamingResponse(self) + + async def create( + self, + bucket_name: str, + *, + storage_id: int, + expiration_days: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Sets up automatic object expiration for an S3 bucket. + + All objects in the bucket + will be automatically deleted after the specified number of days to help manage + storage costs and meet compliance requirements. This applies a global lifecycle + rule to the entire bucket - all existing and future objects will be subject to + the expiration policy. + + Args: + expiration_days: Number of days after which objects will be automatically deleted from the + bucket. Must be a positive integer. Common values: 30 for monthly cleanup, 365 + for yearly retention. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/lifecycle", + body=await async_maybe_transform( + {"expiration_days": expiration_days}, lifecycle_create_params.LifecycleCreateParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def delete( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Removes all lifecycle rules from an S3 bucket, disabling automatic object + expiration. Objects will no longer be automatically deleted based on age. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/lifecycle", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class LifecycleResourceWithRawResponse: + def __init__(self, lifecycle: LifecycleResource) -> None: + self._lifecycle = lifecycle + + self.create = to_raw_response_wrapper( + lifecycle.create, + ) + self.delete = to_raw_response_wrapper( + lifecycle.delete, + ) + + +class AsyncLifecycleResourceWithRawResponse: + def __init__(self, lifecycle: AsyncLifecycleResource) -> None: + self._lifecycle = lifecycle + + self.create = async_to_raw_response_wrapper( + lifecycle.create, + ) + self.delete = async_to_raw_response_wrapper( + lifecycle.delete, + ) + + +class LifecycleResourceWithStreamingResponse: + def __init__(self, lifecycle: LifecycleResource) -> None: + self._lifecycle = lifecycle + + self.create = to_streamed_response_wrapper( + lifecycle.create, + ) + self.delete = to_streamed_response_wrapper( + lifecycle.delete, + ) + + +class AsyncLifecycleResourceWithStreamingResponse: + def __init__(self, lifecycle: AsyncLifecycleResource) -> None: + self._lifecycle = lifecycle + + self.create = async_to_streamed_response_wrapper( + lifecycle.create, + ) + self.delete = async_to_streamed_response_wrapper( + lifecycle.delete, + ) diff --git a/src/gcore/resources/storage/buckets/policy.py b/src/gcore/resources/storage/buckets/policy.py new file mode 100644 index 00000000..cca549f9 --- /dev/null +++ b/src/gcore/resources/storage/buckets/policy.py @@ -0,0 +1,345 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Query, Headers, NoneType, NotGiven, not_given +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.storage.buckets.policy_get_response import PolicyGetResponse + +__all__ = ["PolicyResource", "AsyncPolicyResource"] + + +class PolicyResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> PolicyResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return PolicyResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PolicyResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return PolicyResourceWithStreamingResponse(self) + + def create( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Applies a public read policy to the S3 bucket, allowing anonymous users to + download/access all objects in the bucket via HTTP GET requests. This makes the + bucket suitable for static website hosting, public file sharing, or CDN + integration. Only grants read access - users cannot upload, modify, or delete + objects without proper authentication. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/policy", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def delete( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Removes the public read policy from an S3 bucket, making all objects private and + accessible only with proper authentication credentials. After this operation, + anonymous users will no longer be able to access bucket contents via HTTP + requests. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/policy", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PolicyGetResponse: + """ + Returns whether the S3 bucket is currently configured for public read access. + Shows if anonymous users can download objects from the bucket via HTTP requests. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + return self._get( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/policy", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyGetResponse, + ) + + +class AsyncPolicyResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncPolicyResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncPolicyResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPolicyResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncPolicyResourceWithStreamingResponse(self) + + async def create( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Applies a public read policy to the S3 bucket, allowing anonymous users to + download/access all objects in the bucket via HTTP GET requests. This makes the + bucket suitable for static website hosting, public file sharing, or CDN + integration. Only grants read access - users cannot upload, modify, or delete + objects without proper authentication. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/policy", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def delete( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Removes the public read policy from an S3 bucket, making all objects private and + accessible only with proper authentication credentials. After this operation, + anonymous users will no longer be able to access bucket contents via HTTP + requests. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/policy", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + bucket_name: str, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PolicyGetResponse: + """ + Returns whether the S3 bucket is currently configured for public read access. + Shows if anonymous users can download objects from the bucket via HTTP requests. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not bucket_name: + raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}") + return await self._get( + f"/storage/provisioning/v1/storage/{storage_id}/s3/bucket/{bucket_name}/policy", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PolicyGetResponse, + ) + + +class PolicyResourceWithRawResponse: + def __init__(self, policy: PolicyResource) -> None: + self._policy = policy + + self.create = to_raw_response_wrapper( + policy.create, + ) + self.delete = to_raw_response_wrapper( + policy.delete, + ) + self.get = to_raw_response_wrapper( + policy.get, + ) + + +class AsyncPolicyResourceWithRawResponse: + def __init__(self, policy: AsyncPolicyResource) -> None: + self._policy = policy + + self.create = async_to_raw_response_wrapper( + policy.create, + ) + self.delete = async_to_raw_response_wrapper( + policy.delete, + ) + self.get = async_to_raw_response_wrapper( + policy.get, + ) + + +class PolicyResourceWithStreamingResponse: + def __init__(self, policy: PolicyResource) -> None: + self._policy = policy + + self.create = to_streamed_response_wrapper( + policy.create, + ) + self.delete = to_streamed_response_wrapper( + policy.delete, + ) + self.get = to_streamed_response_wrapper( + policy.get, + ) + + +class AsyncPolicyResourceWithStreamingResponse: + def __init__(self, policy: AsyncPolicyResource) -> None: + self._policy = policy + + self.create = async_to_streamed_response_wrapper( + policy.create, + ) + self.delete = async_to_streamed_response_wrapper( + policy.delete, + ) + self.get = async_to_streamed_response_wrapper( + policy.get, + ) diff --git a/src/gcore/resources/storage/credentials.py b/src/gcore/resources/storage/credentials.py new file mode 100644 index 00000000..616afdb8 --- /dev/null +++ b/src/gcore/resources/storage/credentials.py @@ -0,0 +1,193 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.storage import credential_recreate_params +from ...types.storage.storage import Storage + +__all__ = ["CredentialsResource", "AsyncCredentialsResource"] + + +class CredentialsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CredentialsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return CredentialsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CredentialsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return CredentialsResourceWithStreamingResponse(self) + + def recreate( + self, + storage_id: int, + *, + delete_sftp_password: bool | Omit = omit, + generate_s3_keys: bool | Omit = omit, + generate_sftp_password: bool | Omit = omit, + reset_sftp_keys: bool | Omit = omit, + sftp_password: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Storage: + """ + Generates new access credentials for the storage (S3 keys for S3 storage, SFTP + password for SFTP storage). + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/storage/provisioning/v1/storage/{storage_id}/credentials", + body=maybe_transform( + { + "delete_sftp_password": delete_sftp_password, + "generate_s3_keys": generate_s3_keys, + "generate_sftp_password": generate_sftp_password, + "reset_sftp_keys": reset_sftp_keys, + "sftp_password": sftp_password, + }, + credential_recreate_params.CredentialRecreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Storage, + ) + + +class AsyncCredentialsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCredentialsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncCredentialsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCredentialsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncCredentialsResourceWithStreamingResponse(self) + + async def recreate( + self, + storage_id: int, + *, + delete_sftp_password: bool | Omit = omit, + generate_s3_keys: bool | Omit = omit, + generate_sftp_password: bool | Omit = omit, + reset_sftp_keys: bool | Omit = omit, + sftp_password: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Storage: + """ + Generates new access credentials for the storage (S3 keys for S3 storage, SFTP + password for SFTP storage). + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/storage/provisioning/v1/storage/{storage_id}/credentials", + body=await async_maybe_transform( + { + "delete_sftp_password": delete_sftp_password, + "generate_s3_keys": generate_s3_keys, + "generate_sftp_password": generate_sftp_password, + "reset_sftp_keys": reset_sftp_keys, + "sftp_password": sftp_password, + }, + credential_recreate_params.CredentialRecreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Storage, + ) + + +class CredentialsResourceWithRawResponse: + def __init__(self, credentials: CredentialsResource) -> None: + self._credentials = credentials + + self.recreate = to_raw_response_wrapper( + credentials.recreate, + ) + + +class AsyncCredentialsResourceWithRawResponse: + def __init__(self, credentials: AsyncCredentialsResource) -> None: + self._credentials = credentials + + self.recreate = async_to_raw_response_wrapper( + credentials.recreate, + ) + + +class CredentialsResourceWithStreamingResponse: + def __init__(self, credentials: CredentialsResource) -> None: + self._credentials = credentials + + self.recreate = to_streamed_response_wrapper( + credentials.recreate, + ) + + +class AsyncCredentialsResourceWithStreamingResponse: + def __init__(self, credentials: AsyncCredentialsResource) -> None: + self._credentials = credentials + + self.recreate = async_to_streamed_response_wrapper( + credentials.recreate, + ) diff --git a/src/gcore/resources/storage/locations.py b/src/gcore/resources/storage/locations.py new file mode 100644 index 00000000..bce1aa37 --- /dev/null +++ b/src/gcore/resources/storage/locations.py @@ -0,0 +1,190 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.storage import location_list_params +from ...types.storage.location import Location + +__all__ = ["LocationsResource", "AsyncLocationsResource"] + + +class LocationsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> LocationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return LocationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> LocationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return LocationsResourceWithStreamingResponse(self) + + def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[Location]: + """Returns available storage locations where you can create storages. + + Each location + represents a geographic region with specific data center facilities. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/storage/provisioning/v2/locations", + page=SyncOffsetPage[Location], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + location_list_params.LocationListParams, + ), + ), + model=Location, + ) + + +class AsyncLocationsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncLocationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncLocationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncLocationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncLocationsResourceWithStreamingResponse(self) + + def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Location, AsyncOffsetPage[Location]]: + """Returns available storage locations where you can create storages. + + Each location + represents a geographic region with specific data center facilities. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/storage/provisioning/v2/locations", + page=AsyncOffsetPage[Location], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + location_list_params.LocationListParams, + ), + ), + model=Location, + ) + + +class LocationsResourceWithRawResponse: + def __init__(self, locations: LocationsResource) -> None: + self._locations = locations + + self.list = to_raw_response_wrapper( + locations.list, + ) + + +class AsyncLocationsResourceWithRawResponse: + def __init__(self, locations: AsyncLocationsResource) -> None: + self._locations = locations + + self.list = async_to_raw_response_wrapper( + locations.list, + ) + + +class LocationsResourceWithStreamingResponse: + def __init__(self, locations: LocationsResource) -> None: + self._locations = locations + + self.list = to_streamed_response_wrapper( + locations.list, + ) + + +class AsyncLocationsResourceWithStreamingResponse: + def __init__(self, locations: AsyncLocationsResource) -> None: + self._locations = locations + + self.list = async_to_streamed_response_wrapper( + locations.list, + ) diff --git a/src/gcore/resources/storage/statistics.py b/src/gcore/resources/storage/statistics.py new file mode 100644 index 00000000..dbaf7b6e --- /dev/null +++ b/src/gcore/resources/storage/statistics.py @@ -0,0 +1,364 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.storage import statistic_get_usage_series_params, statistic_get_usage_aggregated_params +from ...types.storage.usage_total import UsageTotal +from ...types.storage.statistic_get_usage_series_response import StatisticGetUsageSeriesResponse + +__all__ = ["StatisticsResource", "AsyncStatisticsResource"] + + +class StatisticsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> StatisticsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return StatisticsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> StatisticsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return StatisticsResourceWithStreamingResponse(self) + + def get_usage_aggregated( + self, + *, + from_: str | Omit = omit, + locations: SequenceNotStr[str] | Omit = omit, + storages: SequenceNotStr[str] | Omit = omit, + to: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageTotal: + """ + Consumption statistics is updated in near real-time as a standard practice. + However, the frequency of updates can vary, but they are typically available + within a 60 minutes period. Exceptions, such as maintenance periods, may delay + data beyond 60 minutes until servers resume and backfill missing statistics. + + Shows storage total usage data in filtered by storages, locations and interval. + + Args: + from_: a From date filter + + locations: a Locations list of filter + + storages: a Storages list of filter + + to: a To date filter + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/storage/stats/v1/storage/usage/total", + body=maybe_transform( + { + "from_": from_, + "locations": locations, + "storages": storages, + "to": to, + }, + statistic_get_usage_aggregated_params.StatisticGetUsageAggregatedParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UsageTotal, + ) + + def get_usage_series( + self, + *, + from_: str | Omit = omit, + granularity: str | Omit = omit, + locations: SequenceNotStr[str] | Omit = omit, + source: int | Omit = omit, + storages: SequenceNotStr[str] | Omit = omit, + to: str | Omit = omit, + ts_string: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StatisticGetUsageSeriesResponse: + """ + Consumption statistics is updated in near real-time as a standard practice. + However, the frequency of updates can vary, but they are typically available + within a 60 minutes period. Exceptions, such as maintenance periods, may delay + data beyond 60 minutes until servers resume and backfill missing statistics. + + Shows storage usage data in series format filtered by clients, storages and + interval. + + Args: + from_: a From date filter + + granularity: a Granularity is period of time for grouping data Valid values are: 1h, 12h, 24h + + locations: a Locations list of filter + + source: a Source is deprecated parameter + + storages: a Storages list of filter + + to: a To date filter + + ts_string: a TsString is configurator of response time format switch response from unix + time format to RFC3339 (2006-01-02T15:04:05Z07:00) + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/storage/stats/v1/storage/usage/series", + body=maybe_transform( + { + "from_": from_, + "granularity": granularity, + "locations": locations, + "source": source, + "storages": storages, + "to": to, + "ts_string": ts_string, + }, + statistic_get_usage_series_params.StatisticGetUsageSeriesParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=StatisticGetUsageSeriesResponse, + ) + + +class AsyncStatisticsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncStatisticsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncStatisticsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncStatisticsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncStatisticsResourceWithStreamingResponse(self) + + async def get_usage_aggregated( + self, + *, + from_: str | Omit = omit, + locations: SequenceNotStr[str] | Omit = omit, + storages: SequenceNotStr[str] | Omit = omit, + to: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UsageTotal: + """ + Consumption statistics is updated in near real-time as a standard practice. + However, the frequency of updates can vary, but they are typically available + within a 60 minutes period. Exceptions, such as maintenance periods, may delay + data beyond 60 minutes until servers resume and backfill missing statistics. + + Shows storage total usage data in filtered by storages, locations and interval. + + Args: + from_: a From date filter + + locations: a Locations list of filter + + storages: a Storages list of filter + + to: a To date filter + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/storage/stats/v1/storage/usage/total", + body=await async_maybe_transform( + { + "from_": from_, + "locations": locations, + "storages": storages, + "to": to, + }, + statistic_get_usage_aggregated_params.StatisticGetUsageAggregatedParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=UsageTotal, + ) + + async def get_usage_series( + self, + *, + from_: str | Omit = omit, + granularity: str | Omit = omit, + locations: SequenceNotStr[str] | Omit = omit, + source: int | Omit = omit, + storages: SequenceNotStr[str] | Omit = omit, + to: str | Omit = omit, + ts_string: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StatisticGetUsageSeriesResponse: + """ + Consumption statistics is updated in near real-time as a standard practice. + However, the frequency of updates can vary, but they are typically available + within a 60 minutes period. Exceptions, such as maintenance periods, may delay + data beyond 60 minutes until servers resume and backfill missing statistics. + + Shows storage usage data in series format filtered by clients, storages and + interval. + + Args: + from_: a From date filter + + granularity: a Granularity is period of time for grouping data Valid values are: 1h, 12h, 24h + + locations: a Locations list of filter + + source: a Source is deprecated parameter + + storages: a Storages list of filter + + to: a To date filter + + ts_string: a TsString is configurator of response time format switch response from unix + time format to RFC3339 (2006-01-02T15:04:05Z07:00) + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/storage/stats/v1/storage/usage/series", + body=await async_maybe_transform( + { + "from_": from_, + "granularity": granularity, + "locations": locations, + "source": source, + "storages": storages, + "to": to, + "ts_string": ts_string, + }, + statistic_get_usage_series_params.StatisticGetUsageSeriesParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=StatisticGetUsageSeriesResponse, + ) + + +class StatisticsResourceWithRawResponse: + def __init__(self, statistics: StatisticsResource) -> None: + self._statistics = statistics + + self.get_usage_aggregated = to_raw_response_wrapper( + statistics.get_usage_aggregated, + ) + self.get_usage_series = to_raw_response_wrapper( + statistics.get_usage_series, + ) + + +class AsyncStatisticsResourceWithRawResponse: + def __init__(self, statistics: AsyncStatisticsResource) -> None: + self._statistics = statistics + + self.get_usage_aggregated = async_to_raw_response_wrapper( + statistics.get_usage_aggregated, + ) + self.get_usage_series = async_to_raw_response_wrapper( + statistics.get_usage_series, + ) + + +class StatisticsResourceWithStreamingResponse: + def __init__(self, statistics: StatisticsResource) -> None: + self._statistics = statistics + + self.get_usage_aggregated = to_streamed_response_wrapper( + statistics.get_usage_aggregated, + ) + self.get_usage_series = to_streamed_response_wrapper( + statistics.get_usage_series, + ) + + +class AsyncStatisticsResourceWithStreamingResponse: + def __init__(self, statistics: AsyncStatisticsResource) -> None: + self._statistics = statistics + + self.get_usage_aggregated = async_to_streamed_response_wrapper( + statistics.get_usage_aggregated, + ) + self.get_usage_series = async_to_streamed_response_wrapper( + statistics.get_usage_series, + ) diff --git a/src/gcore/resources/storage/storage.py b/src/gcore/resources/storage/storage.py new file mode 100644 index 00000000..afc3922f --- /dev/null +++ b/src/gcore/resources/storage/storage.py @@ -0,0 +1,1050 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from .locations import ( + LocationsResource, + AsyncLocationsResource, + LocationsResourceWithRawResponse, + AsyncLocationsResourceWithRawResponse, + LocationsResourceWithStreamingResponse, + AsyncLocationsResourceWithStreamingResponse, +) +from .statistics import ( + StatisticsResource, + AsyncStatisticsResource, + StatisticsResourceWithRawResponse, + AsyncStatisticsResourceWithRawResponse, + StatisticsResourceWithStreamingResponse, + AsyncStatisticsResourceWithStreamingResponse, +) +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .credentials import ( + CredentialsResource, + AsyncCredentialsResource, + CredentialsResourceWithRawResponse, + AsyncCredentialsResourceWithRawResponse, + CredentialsResourceWithStreamingResponse, + AsyncCredentialsResourceWithStreamingResponse, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ..._base_client import AsyncPaginator, make_request_options +from ...types.storage import storage_list_params, storage_create_params, storage_update_params, storage_restore_params +from .buckets.buckets import ( + BucketsResource, + AsyncBucketsResource, + BucketsResourceWithRawResponse, + AsyncBucketsResourceWithRawResponse, + BucketsResourceWithStreamingResponse, + AsyncBucketsResourceWithStreamingResponse, +) +from ...types.storage.storage import Storage + +__all__ = ["StorageResource", "AsyncStorageResource"] + + +class StorageResource(SyncAPIResource): + @cached_property + def locations(self) -> LocationsResource: + return LocationsResource(self._client) + + @cached_property + def statistics(self) -> StatisticsResource: + return StatisticsResource(self._client) + + @cached_property + def credentials(self) -> CredentialsResource: + return CredentialsResource(self._client) + + @cached_property + def buckets(self) -> BucketsResource: + return BucketsResource(self._client) + + @cached_property + def with_raw_response(self) -> StorageResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return StorageResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> StorageResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return StorageResourceWithStreamingResponse(self) + + def create( + self, + *, + location: str, + name: str, + type: Literal["sftp", "s3"], + generate_sftp_password: bool | Omit = omit, + sftp_password: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Storage: + """ + Creates a new storage instance (S3 or SFTP) in the specified location and + returns the storage details including credentials. + + Args: + location: Geographic location where the storage will be provisioned. Each location + represents a specific data center region. + + name: Unique storage name identifier. Must contain only letters, numbers, dashes, and + underscores. Cannot be empty and must be less than 256 characters. + + type: Storage protocol type. Choose 's3' for S3-compatible object storage with API + access, or `sftp` for SFTP file transfer protocol. + + generate_sftp_password: Automatically generate a secure password for SFTP storage access. Only + applicable when type is `sftp`. When `true`, a random password will be generated + and returned in the response. + + sftp_password: Custom password for SFTP storage access. Only applicable when type is `sftp`. If + not provided and `generate_sftp_password` is `false`, no password authentication + will be available. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/storage/provisioning/v2/storage", + body=maybe_transform( + { + "location": location, + "name": name, + "type": type, + "generate_sftp_password": generate_sftp_password, + "sftp_password": sftp_password, + }, + storage_create_params.StorageCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Storage, + ) + + def update( + self, + storage_id: int, + *, + expires: str | Omit = omit, + server_alias: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Storage: + """Updates storage configuration such as expiration date and server alias. + + Used for + SFTP storages. + + Args: + expires: Duration when the storage should expire in format like "1 years 6 months 2 weeks + 3 days 5 hours 10 minutes 15 seconds". Set empty to remove expiration. + + server_alias: Custom domain alias for accessing the storage. Set empty to remove alias. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/storage/provisioning/v2/storage/{storage_id}", + body=maybe_transform( + { + "expires": expires, + "server_alias": server_alias, + }, + storage_update_params.StorageUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Storage, + ) + + def list( + self, + *, + id: str | Omit = omit, + limit: int | Omit = omit, + location: str | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: str | Omit = omit, + order_direction: Literal["asc", "desc"] | Omit = omit, + show_deleted: bool | Omit = omit, + status: Literal["active", "suspended", "deleted", "pending"] | Omit = omit, + type: Literal["s3", "sftp"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[Storage]: + """ + Returns storages with the same filtering and pagination as v2, but in a + simplified response shape for easier client consumption. + + Response format: count: total number of storages matching the filter + (independent of pagination) results: the current page of storages according to + limit/offset + + Args: + id: Filter by storage ID + + limit: Max number of records in response + + location: Filter by storage location/region + + name: Filter by storage name (exact match) + + offset: Number of records to skip before beginning to write in response. + + order_by: Field name to sort by + + order_direction: Ascending or descending order + + show_deleted: Include deleted storages in the response + + status: Filter by storage status + + type: Filter by storage type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/storage/provisioning/v3/storage", + page=SyncOffsetPage[Storage], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "id": id, + "limit": limit, + "location": location, + "name": name, + "offset": offset, + "order_by": order_by, + "order_direction": order_direction, + "show_deleted": show_deleted, + "status": status, + "type": type, + }, + storage_list_params.StorageListParams, + ), + ), + model=Storage, + ) + + def delete( + self, + storage_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Permanently deletes a storage and all its data. + + This action cannot be undone. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/storage/provisioning/v1/storage/{storage_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + storage_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Storage: + """ + Retrieves detailed information about a specific storage including its + configuration, credentials, and current status. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/storage/provisioning/v1/storage/{storage_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Storage, + ) + + def link_ssh_key( + self, + key_id: int, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Associates an SSH public key with an SFTP storage, enabling passwordless + authentication. Only works with SFTP storage types - not applicable to + S3-compatible storage. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/storage/provisioning/v1/storage/{storage_id}/key/{key_id}/link", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def restore( + self, + storage_id: int, + *, + client_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Restores a previously deleted S3 storage if it was deleted within the last 2 + weeks. SFTP storages cannot be restored. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/storage/provisioning/v1/storage/{storage_id}/restore", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"client_id": client_id}, storage_restore_params.StorageRestoreParams), + ), + cast_to=NoneType, + ) + + def unlink_ssh_key( + self, + key_id: int, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Removes SSH key association from an SFTP storage, disabling passwordless + authentication for that key. The key itself remains available for other + storages. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/storage/provisioning/v1/storage/{storage_id}/key/{key_id}/unlink", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncStorageResource(AsyncAPIResource): + @cached_property + def locations(self) -> AsyncLocationsResource: + return AsyncLocationsResource(self._client) + + @cached_property + def statistics(self) -> AsyncStatisticsResource: + return AsyncStatisticsResource(self._client) + + @cached_property + def credentials(self) -> AsyncCredentialsResource: + return AsyncCredentialsResource(self._client) + + @cached_property + def buckets(self) -> AsyncBucketsResource: + return AsyncBucketsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncStorageResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncStorageResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncStorageResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncStorageResourceWithStreamingResponse(self) + + async def create( + self, + *, + location: str, + name: str, + type: Literal["sftp", "s3"], + generate_sftp_password: bool | Omit = omit, + sftp_password: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Storage: + """ + Creates a new storage instance (S3 or SFTP) in the specified location and + returns the storage details including credentials. + + Args: + location: Geographic location where the storage will be provisioned. Each location + represents a specific data center region. + + name: Unique storage name identifier. Must contain only letters, numbers, dashes, and + underscores. Cannot be empty and must be less than 256 characters. + + type: Storage protocol type. Choose 's3' for S3-compatible object storage with API + access, or `sftp` for SFTP file transfer protocol. + + generate_sftp_password: Automatically generate a secure password for SFTP storage access. Only + applicable when type is `sftp`. When `true`, a random password will be generated + and returned in the response. + + sftp_password: Custom password for SFTP storage access. Only applicable when type is `sftp`. If + not provided and `generate_sftp_password` is `false`, no password authentication + will be available. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/storage/provisioning/v2/storage", + body=await async_maybe_transform( + { + "location": location, + "name": name, + "type": type, + "generate_sftp_password": generate_sftp_password, + "sftp_password": sftp_password, + }, + storage_create_params.StorageCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Storage, + ) + + async def update( + self, + storage_id: int, + *, + expires: str | Omit = omit, + server_alias: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Storage: + """Updates storage configuration such as expiration date and server alias. + + Used for + SFTP storages. + + Args: + expires: Duration when the storage should expire in format like "1 years 6 months 2 weeks + 3 days 5 hours 10 minutes 15 seconds". Set empty to remove expiration. + + server_alias: Custom domain alias for accessing the storage. Set empty to remove alias. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/storage/provisioning/v2/storage/{storage_id}", + body=await async_maybe_transform( + { + "expires": expires, + "server_alias": server_alias, + }, + storage_update_params.StorageUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Storage, + ) + + def list( + self, + *, + id: str | Omit = omit, + limit: int | Omit = omit, + location: str | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + order_by: str | Omit = omit, + order_direction: Literal["asc", "desc"] | Omit = omit, + show_deleted: bool | Omit = omit, + status: Literal["active", "suspended", "deleted", "pending"] | Omit = omit, + type: Literal["s3", "sftp"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Storage, AsyncOffsetPage[Storage]]: + """ + Returns storages with the same filtering and pagination as v2, but in a + simplified response shape for easier client consumption. + + Response format: count: total number of storages matching the filter + (independent of pagination) results: the current page of storages according to + limit/offset + + Args: + id: Filter by storage ID + + limit: Max number of records in response + + location: Filter by storage location/region + + name: Filter by storage name (exact match) + + offset: Number of records to skip before beginning to write in response. + + order_by: Field name to sort by + + order_direction: Ascending or descending order + + show_deleted: Include deleted storages in the response + + status: Filter by storage status + + type: Filter by storage type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/storage/provisioning/v3/storage", + page=AsyncOffsetPage[Storage], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "id": id, + "limit": limit, + "location": location, + "name": name, + "offset": offset, + "order_by": order_by, + "order_direction": order_direction, + "show_deleted": show_deleted, + "status": status, + "type": type, + }, + storage_list_params.StorageListParams, + ), + ), + model=Storage, + ) + + async def delete( + self, + storage_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Permanently deletes a storage and all its data. + + This action cannot be undone. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/storage/provisioning/v1/storage/{storage_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + storage_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Storage: + """ + Retrieves detailed information about a specific storage including its + configuration, credentials, and current status. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/storage/provisioning/v1/storage/{storage_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Storage, + ) + + async def link_ssh_key( + self, + key_id: int, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Associates an SSH public key with an SFTP storage, enabling passwordless + authentication. Only works with SFTP storage types - not applicable to + S3-compatible storage. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/storage/provisioning/v1/storage/{storage_id}/key/{key_id}/link", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def restore( + self, + storage_id: int, + *, + client_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Restores a previously deleted S3 storage if it was deleted within the last 2 + weeks. SFTP storages cannot be restored. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/storage/provisioning/v1/storage/{storage_id}/restore", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"client_id": client_id}, storage_restore_params.StorageRestoreParams + ), + ), + cast_to=NoneType, + ) + + async def unlink_ssh_key( + self, + key_id: int, + *, + storage_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Removes SSH key association from an SFTP storage, disabling passwordless + authentication for that key. The key itself remains available for other + storages. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/storage/provisioning/v1/storage/{storage_id}/key/{key_id}/unlink", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class StorageResourceWithRawResponse: + def __init__(self, storage: StorageResource) -> None: + self._storage = storage + + self.create = to_raw_response_wrapper( + storage.create, + ) + self.update = to_raw_response_wrapper( + storage.update, + ) + self.list = to_raw_response_wrapper( + storage.list, + ) + self.delete = to_raw_response_wrapper( + storage.delete, + ) + self.get = to_raw_response_wrapper( + storage.get, + ) + self.link_ssh_key = to_raw_response_wrapper( + storage.link_ssh_key, + ) + self.restore = to_raw_response_wrapper( + storage.restore, + ) + self.unlink_ssh_key = to_raw_response_wrapper( + storage.unlink_ssh_key, + ) + + @cached_property + def locations(self) -> LocationsResourceWithRawResponse: + return LocationsResourceWithRawResponse(self._storage.locations) + + @cached_property + def statistics(self) -> StatisticsResourceWithRawResponse: + return StatisticsResourceWithRawResponse(self._storage.statistics) + + @cached_property + def credentials(self) -> CredentialsResourceWithRawResponse: + return CredentialsResourceWithRawResponse(self._storage.credentials) + + @cached_property + def buckets(self) -> BucketsResourceWithRawResponse: + return BucketsResourceWithRawResponse(self._storage.buckets) + + +class AsyncStorageResourceWithRawResponse: + def __init__(self, storage: AsyncStorageResource) -> None: + self._storage = storage + + self.create = async_to_raw_response_wrapper( + storage.create, + ) + self.update = async_to_raw_response_wrapper( + storage.update, + ) + self.list = async_to_raw_response_wrapper( + storage.list, + ) + self.delete = async_to_raw_response_wrapper( + storage.delete, + ) + self.get = async_to_raw_response_wrapper( + storage.get, + ) + self.link_ssh_key = async_to_raw_response_wrapper( + storage.link_ssh_key, + ) + self.restore = async_to_raw_response_wrapper( + storage.restore, + ) + self.unlink_ssh_key = async_to_raw_response_wrapper( + storage.unlink_ssh_key, + ) + + @cached_property + def locations(self) -> AsyncLocationsResourceWithRawResponse: + return AsyncLocationsResourceWithRawResponse(self._storage.locations) + + @cached_property + def statistics(self) -> AsyncStatisticsResourceWithRawResponse: + return AsyncStatisticsResourceWithRawResponse(self._storage.statistics) + + @cached_property + def credentials(self) -> AsyncCredentialsResourceWithRawResponse: + return AsyncCredentialsResourceWithRawResponse(self._storage.credentials) + + @cached_property + def buckets(self) -> AsyncBucketsResourceWithRawResponse: + return AsyncBucketsResourceWithRawResponse(self._storage.buckets) + + +class StorageResourceWithStreamingResponse: + def __init__(self, storage: StorageResource) -> None: + self._storage = storage + + self.create = to_streamed_response_wrapper( + storage.create, + ) + self.update = to_streamed_response_wrapper( + storage.update, + ) + self.list = to_streamed_response_wrapper( + storage.list, + ) + self.delete = to_streamed_response_wrapper( + storage.delete, + ) + self.get = to_streamed_response_wrapper( + storage.get, + ) + self.link_ssh_key = to_streamed_response_wrapper( + storage.link_ssh_key, + ) + self.restore = to_streamed_response_wrapper( + storage.restore, + ) + self.unlink_ssh_key = to_streamed_response_wrapper( + storage.unlink_ssh_key, + ) + + @cached_property + def locations(self) -> LocationsResourceWithStreamingResponse: + return LocationsResourceWithStreamingResponse(self._storage.locations) + + @cached_property + def statistics(self) -> StatisticsResourceWithStreamingResponse: + return StatisticsResourceWithStreamingResponse(self._storage.statistics) + + @cached_property + def credentials(self) -> CredentialsResourceWithStreamingResponse: + return CredentialsResourceWithStreamingResponse(self._storage.credentials) + + @cached_property + def buckets(self) -> BucketsResourceWithStreamingResponse: + return BucketsResourceWithStreamingResponse(self._storage.buckets) + + +class AsyncStorageResourceWithStreamingResponse: + def __init__(self, storage: AsyncStorageResource) -> None: + self._storage = storage + + self.create = async_to_streamed_response_wrapper( + storage.create, + ) + self.update = async_to_streamed_response_wrapper( + storage.update, + ) + self.list = async_to_streamed_response_wrapper( + storage.list, + ) + self.delete = async_to_streamed_response_wrapper( + storage.delete, + ) + self.get = async_to_streamed_response_wrapper( + storage.get, + ) + self.link_ssh_key = async_to_streamed_response_wrapper( + storage.link_ssh_key, + ) + self.restore = async_to_streamed_response_wrapper( + storage.restore, + ) + self.unlink_ssh_key = async_to_streamed_response_wrapper( + storage.unlink_ssh_key, + ) + + @cached_property + def locations(self) -> AsyncLocationsResourceWithStreamingResponse: + return AsyncLocationsResourceWithStreamingResponse(self._storage.locations) + + @cached_property + def statistics(self) -> AsyncStatisticsResourceWithStreamingResponse: + return AsyncStatisticsResourceWithStreamingResponse(self._storage.statistics) + + @cached_property + def credentials(self) -> AsyncCredentialsResourceWithStreamingResponse: + return AsyncCredentialsResourceWithStreamingResponse(self._storage.credentials) + + @cached_property + def buckets(self) -> AsyncBucketsResourceWithStreamingResponse: + return AsyncBucketsResourceWithStreamingResponse(self._storage.buckets) diff --git a/src/gcore/resources/streaming/__init__.py b/src/gcore/resources/streaming/__init__.py new file mode 100644 index 00000000..705ade73 --- /dev/null +++ b/src/gcore/resources/streaming/__init__.py @@ -0,0 +1,159 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .videos import ( + VideosResource, + AsyncVideosResource, + VideosResourceWithRawResponse, + AsyncVideosResourceWithRawResponse, + VideosResourceWithStreamingResponse, + AsyncVideosResourceWithStreamingResponse, +) +from .players import ( + PlayersResource, + AsyncPlayersResource, + PlayersResourceWithRawResponse, + AsyncPlayersResourceWithRawResponse, + PlayersResourceWithStreamingResponse, + AsyncPlayersResourceWithStreamingResponse, +) +from .streams import ( + StreamsResource, + AsyncStreamsResource, + StreamsResourceWithRawResponse, + AsyncStreamsResourceWithRawResponse, + StreamsResourceWithStreamingResponse, + AsyncStreamsResourceWithStreamingResponse, +) +from .ai_tasks import ( + AITasksResource, + AsyncAITasksResource, + AITasksResourceWithRawResponse, + AsyncAITasksResourceWithRawResponse, + AITasksResourceWithStreamingResponse, + AsyncAITasksResourceWithStreamingResponse, +) +from .playlists import ( + PlaylistsResource, + AsyncPlaylistsResource, + PlaylistsResourceWithRawResponse, + AsyncPlaylistsResourceWithRawResponse, + PlaylistsResourceWithStreamingResponse, + AsyncPlaylistsResourceWithStreamingResponse, +) +from .restreams import ( + RestreamsResource, + AsyncRestreamsResource, + RestreamsResourceWithRawResponse, + AsyncRestreamsResourceWithRawResponse, + RestreamsResourceWithStreamingResponse, + AsyncRestreamsResourceWithStreamingResponse, +) +from .streaming import ( + StreamingResource, + AsyncStreamingResource, + StreamingResourceWithRawResponse, + AsyncStreamingResourceWithRawResponse, + StreamingResourceWithStreamingResponse, + AsyncStreamingResourceWithStreamingResponse, +) +from .broadcasts import ( + BroadcastsResource, + AsyncBroadcastsResource, + BroadcastsResourceWithRawResponse, + AsyncBroadcastsResourceWithRawResponse, + BroadcastsResourceWithStreamingResponse, + AsyncBroadcastsResourceWithStreamingResponse, +) +from .statistics import ( + StatisticsResource, + AsyncStatisticsResource, + StatisticsResourceWithRawResponse, + AsyncStatisticsResourceWithRawResponse, + StatisticsResourceWithStreamingResponse, + AsyncStatisticsResourceWithStreamingResponse, +) +from .directories import ( + DirectoriesResource, + AsyncDirectoriesResource, + DirectoriesResourceWithRawResponse, + AsyncDirectoriesResourceWithRawResponse, + DirectoriesResourceWithStreamingResponse, + AsyncDirectoriesResourceWithStreamingResponse, +) +from .quality_sets import ( + QualitySetsResource, + AsyncQualitySetsResource, + QualitySetsResourceWithRawResponse, + AsyncQualitySetsResourceWithRawResponse, + QualitySetsResourceWithStreamingResponse, + AsyncQualitySetsResourceWithStreamingResponse, +) + +__all__ = [ + "AITasksResource", + "AsyncAITasksResource", + "AITasksResourceWithRawResponse", + "AsyncAITasksResourceWithRawResponse", + "AITasksResourceWithStreamingResponse", + "AsyncAITasksResourceWithStreamingResponse", + "BroadcastsResource", + "AsyncBroadcastsResource", + "BroadcastsResourceWithRawResponse", + "AsyncBroadcastsResourceWithRawResponse", + "BroadcastsResourceWithStreamingResponse", + "AsyncBroadcastsResourceWithStreamingResponse", + "DirectoriesResource", + "AsyncDirectoriesResource", + "DirectoriesResourceWithRawResponse", + "AsyncDirectoriesResourceWithRawResponse", + "DirectoriesResourceWithStreamingResponse", + "AsyncDirectoriesResourceWithStreamingResponse", + "PlayersResource", + "AsyncPlayersResource", + "PlayersResourceWithRawResponse", + "AsyncPlayersResourceWithRawResponse", + "PlayersResourceWithStreamingResponse", + "AsyncPlayersResourceWithStreamingResponse", + "QualitySetsResource", + "AsyncQualitySetsResource", + "QualitySetsResourceWithRawResponse", + "AsyncQualitySetsResourceWithRawResponse", + "QualitySetsResourceWithStreamingResponse", + "AsyncQualitySetsResourceWithStreamingResponse", + "PlaylistsResource", + "AsyncPlaylistsResource", + "PlaylistsResourceWithRawResponse", + "AsyncPlaylistsResourceWithRawResponse", + "PlaylistsResourceWithStreamingResponse", + "AsyncPlaylistsResourceWithStreamingResponse", + "VideosResource", + "AsyncVideosResource", + "VideosResourceWithRawResponse", + "AsyncVideosResourceWithRawResponse", + "VideosResourceWithStreamingResponse", + "AsyncVideosResourceWithStreamingResponse", + "StreamsResource", + "AsyncStreamsResource", + "StreamsResourceWithRawResponse", + "AsyncStreamsResourceWithRawResponse", + "StreamsResourceWithStreamingResponse", + "AsyncStreamsResourceWithStreamingResponse", + "RestreamsResource", + "AsyncRestreamsResource", + "RestreamsResourceWithRawResponse", + "AsyncRestreamsResourceWithRawResponse", + "RestreamsResourceWithStreamingResponse", + "AsyncRestreamsResourceWithStreamingResponse", + "StatisticsResource", + "AsyncStatisticsResource", + "StatisticsResourceWithRawResponse", + "AsyncStatisticsResourceWithRawResponse", + "StatisticsResourceWithStreamingResponse", + "AsyncStatisticsResourceWithStreamingResponse", + "StreamingResource", + "AsyncStreamingResource", + "StreamingResourceWithRawResponse", + "AsyncStreamingResourceWithRawResponse", + "StreamingResourceWithStreamingResponse", + "AsyncStreamingResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/streaming/ai_tasks.py b/src/gcore/resources/streaming/ai_tasks.py new file mode 100644 index 00000000..bb85c829 --- /dev/null +++ b/src/gcore/resources/streaming/ai_tasks.py @@ -0,0 +1,1374 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncPageStreamingAI, AsyncPageStreamingAI +from ..._base_client import AsyncPaginator, make_request_options +from ...types.streaming import ai_task_list_params, ai_task_create_params, ai_task_get_ai_settings_params +from ...types.streaming.ai_task import AITask +from ...types.streaming.ai_task_get_response import AITaskGetResponse +from ...types.streaming.ai_task_cancel_response import AITaskCancelResponse +from ...types.streaming.ai_task_create_response import AITaskCreateResponse +from ...types.streaming.ai_task_get_ai_settings_response import AITaskGetAISettingsResponse + +__all__ = ["AITasksResource", "AsyncAITasksResource"] + + +class AITasksResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> AITasksResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AITasksResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AITasksResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AITasksResourceWithStreamingResponse(self) + + def create( + self, + *, + task_name: Literal["transcription", "content-moderation"], + url: str, + audio_language: str | Omit = omit, + category: Literal["sport", "nsfw", "hard_nudity", "soft_nudity"] | Omit = omit, + client_entity_data: str | Omit = omit, + client_user_id: str | Omit = omit, + subtitles_language: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AITaskCreateResponse: + """ + Creating an AI task. + + This method allows you to create an AI task for VOD video processing: + + - ASR: Transcribe video + - ASR: Translate subtitles + - CM: Sports detection + - CM: Not Safe For Work (NSFW) content detection + - CM: Soft nudity detection + - CM: Hard nudity detection + - CM: Objects recognition (soon) + + ![Auto generated subtitles example](https://demo-files.gvideo.io/apidocs/captions.gif) + + How to use: + + - Create an AI task, specify algoritm to use + - Get `task_id` + - Check a result using `.../ai/tasks/{task_id}` method + + For more detailed information, see the description of each method separately. + + **AI Automatic Speech Recognition (ASR)** + + AI is instrumental in automatic video processing for subtitles creation by using + Automatic Speech Recognition (ASR) technology to transcribe spoken words into + text, which can then be translated into multiple languages for broader + accessibility. + + Categories: + + - `transcription` – to create subtitles/captions from audio in the original + language. + - `translation` – to transate subtitles/captions from the original language to + 99+ other languages. + + AI subtitle transcription and translation tools are highly efficient, processing + large volumes of audio-visual content quickly and providing accurate + transcriptions and translations with minimal human intervention. Additionally, + AI-driven solutions can significantly reduce costs and turnaround times compared + to traditional methods, making them an invaluable resource for content creators + and broadcasters aiming to reach global audiences. + + Example response with positive result: + + ``` + { + "status": "SUCCESS", + "result": { + "subtitles": [ + { + "start_time": "00:00:00.031", + "end_time": "00:00:03.831", + "text": "Come on team, ..." + }, ... + ] + "vttContent": "WEBVTT\n\n1\n00:00:00.031 --> 00:00:03.831\nCome on team, ...", + "concatenated_text": "Come on team, ...", + "languages": [ "eng" ], + "speech_detected": true + } + }, ... + } + ``` + + **AI Content Moderation (CM)** + + The AI Content Moderation API offers a powerful solution for analyzing video + content to detect various categories of inappropriate material. Leveraging + state-of-the-art AI models, this API ensures real-time analysis and flagging of + sensitive or restricted content types, making it an essential tool for platforms + requiring stringent content moderation. + + Categories: + + - `nsfw`: Quick algorithm to detect pornographic material, ensuring content is + "not-safe-for-work" or normal. + - `hard_nudity`: Detailed analisys of video which detects explicit nudity + involving genitalia. + - `soft_nudity`: Detailed video analysis that reveals both explicit and partial + nudity, including the presence of male and female faces and other uncovered + body parts. + - `sport`: Recognizes various sporting activities. + + The AI Content Moderation API is an invaluable tool for managing and controlling + the type of content being shared or streamed on your platform. By implementing + this API, you can ensure compliance with community guidelines and legal + requirements, as well as provide a safer environment for your users. + + Important notes: + + - It's allowed to analyse still images too (where applicable). Format of image: + JPEG, PNG. In that case one image is the same as video of 1 second duration. + - Not all frames in the video are used for analysis, but only key frames + (Iframe). For example, if a key frame in a video is set every ±2 seconds, then + detection will only occur at these timestamps. If an object appears and + disappears between these time stamps, it will not be detected. We are working + on a version to analyze more frames, please contact your manager or our + support team to enable this method. + + Example response with positive result: + + ``` + { + "status": "SUCCESS", + "result": { + "nsfw_detected": true, + "detection_results": ["nsfw"], + "frames": [{"label": "nsfw", "confidence": 1.0, "frame_number": 24}, ...], + }, + } + ``` + + **Additional information** + + Billing takes into account the duration of the analyzed video. Or the duration + until the stop tag(where applicable), if the condition was triggered during the + analysis. + + The heart of content moderation is AI, with additional services. They run on our + own infrastructure, so the files/data are not transferred anywhere to external + services. After processing, original files are also deleted from local storage + of AI. + + Read more detailed information about our solution, and architecture, and + benefits in the knowledge base and blog. + + Args: + task_name: Name of the task to be performed + + url: URL to the MP4 file to analyse. File must be publicly accessible via HTTP/HTTPS. + + audio_language: Language in original audio (transcription only). This value is used to determine + the language from which to transcribe. + + If this is not set, the system will run auto language identification and the + subtitles will be in the detected language. The method also works based on AI + analysis. It's fairly accurate, but if it's wrong, then set the language + explicitly. + + Additionally, when this is not set, we also support recognition of alternate + languages in the video (language code-switching). + + Language is set by 3-letter language code according to ISO-639-2 (bibliographic + code). + + We can process languages: + + - 'afr': Afrikaans + - 'alb': Albanian + - 'amh': Amharic + - 'ara': Arabic + - 'arm': Armenian + - 'asm': Assamese + - 'aze': Azerbaijani + - 'bak': Bashkir + - 'baq': Basque + - 'bel': Belarusian + - 'ben': Bengali + - 'bos': Bosnian + - 'bre': Breton + - 'bul': Bulgarian + - 'bur': Myanmar + - 'cat': Catalan + - 'chi': Chinese + - 'cze': Czech + - 'dan': Danish + - 'dut': Nynorsk + - 'eng': English + - 'est': Estonian + - 'fao': Faroese + - 'fin': Finnish + - 'fre': French + - 'geo': Georgian + - 'ger': German + - 'glg': Galician + - 'gre': Greek + - 'guj': Gujarati + - 'hat': Haitian creole + - 'hau': Hausa + - 'haw': Hawaiian + - 'heb': Hebrew + - 'hin': Hindi + - 'hrv': Croatian + - 'hun': Hungarian + - 'ice': Icelandic + - 'ind': Indonesian + - 'ita': Italian + - 'jav': Javanese + - 'jpn': Japanese + - 'kan': Kannada + - 'kaz': Kazakh + - 'khm': Khmer + - 'kor': Korean + - 'lao': Lao + - 'lat': Latin + - 'lav': Latvian + - 'lin': Lingala + - 'lit': Lithuanian + - 'ltz': Luxembourgish + - 'mac': Macedonian + - 'mal': Malayalam + - 'mao': Maori + - 'mar': Marathi + - 'may': Malay + - 'mlg': Malagasy + - 'mlt': Maltese + - 'mon': Mongolian + - 'nep': Nepali + - 'dut': Dutch + - 'nor': Norwegian + - 'oci': Occitan + - 'pan': Punjabi + - 'per': Persian + - 'pol': Polish + - 'por': Portuguese + - 'pus': Pashto + - 'rum': Romanian + - 'rus': Russian + - 'san': Sanskrit + - 'sin': Sinhala + - 'slo': Slovak + - 'slv': Slovenian + - 'sna': Shona + - 'snd': Sindhi + - 'som': Somali + - 'spa': Spanish + - 'srp': Serbian + - 'sun': Sundanese + - 'swa': Swahili + - 'swe': Swedish + - 'tam': Tamil + - 'tat': Tatar + - 'tel': Telugu + - 'tgk': Tajik + - 'tgl': Tagalog + - 'tha': Thai + - 'tib': Tibetan + - 'tuk': Turkmen + - 'tur': Turkish + - 'ukr': Ukrainian + - 'urd': Urdu + - 'uzb': Uzbek + - 'vie': Vietnamese + - 'wel': Welsh + - 'yid': Yiddish + - 'yor': Yoruba + + category: Model for analysis (content-moderation only). Determines what exactly needs to + be found in the video. + + client_entity_data: Meta parameter, designed to store your own extra information about a video + entity: video source, video id, etc. It is not used in any way in video + processing. + + For example, if an AI-task was created automatically when you uploaded a video + with the AI auto-processing option (nudity detection, etc), then the ID of the + associated video for which the task was performed will be explicitly indicated + here. + + client_user_id: Meta parameter, designed to store your own identifier. Can be used by you to tag + requests from different end-users. It is not used in any way in video + processing. + + subtitles_language: Indicates which language it is clearly necessary to translate into. If this is + not set, the original language will be used from attribute "audio_language". + + Please note that: + + - transcription into the original language is a free procedure, + - and translation from the original language into any other languages is a + "translation" procedure and is paid. More details in + [POST /streaming/ai/tasks#transcribe](/docs/api-reference/streaming/ai/create-ai-asr-task). + Language is set by 3-letter language code according to ISO-639-2 + (bibliographic code). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/streaming/ai/tasks", + body=maybe_transform( + { + "task_name": task_name, + "url": url, + "audio_language": audio_language, + "category": category, + "client_entity_data": client_entity_data, + "client_user_id": client_user_id, + "subtitles_language": subtitles_language, + }, + ai_task_create_params.AITaskCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AITaskCreateResponse, + ) + + def list( + self, + *, + date_created: str | Omit = omit, + limit: int | Omit = omit, + ordering: Literal["task_id", "status", "task_name", "started_at"] | Omit = omit, + page: int | Omit = omit, + search: str | Omit = omit, + status: Literal["FAILURE", "PENDING", "RECEIVED", "RETRY", "REVOKED", "STARTED", "SUCCESS"] | Omit = omit, + task_id: str | Omit = omit, + task_name: Literal["transcription", "content-moderation"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncPageStreamingAI[AITask]: + """ + Returns a list of previously created and processed AI tasks. + + The list contains brief information about the task and its execution status. + Data is displayed page by page. + + Args: + date_created: Time when task was created. Datetime in ISO 8601 format. + + limit: Number of results to return per page. + + ordering: Which field to use when ordering the results: `task_id`, status, and + `task_name`. Sorting is done in ascending (ASC) order. + + If parameter is omitted then "started_at DESC" is used for ordering by default. + + page: Page to view from task list, starting from 1 + + search: This is an field for combined text search in the following fields: `task_id`, + `task_name`, status, and `task_data`. + + Both full and partial searches are possible inside specified above fields. For + example, you can filter tasks of a certain category, or tasks by a specific + original file. + + Example: + + - To filter tasks of Content Moderation NSFW method: + `GET /streaming/ai/tasks?search=nsfw` + - To filter tasks of processing video from a specific origin: + `GET /streaming/ai/tasks?search=s3.eu-west-1.amazonaws.com` + + status: Task status + + task_id: The task unique identifier to fiund + + task_name: Type of the AI task. Reflects the original API method that was used to create + the AI task. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/ai/tasks", + page=SyncPageStreamingAI[AITask], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_created": date_created, + "limit": limit, + "ordering": ordering, + "page": page, + "search": search, + "status": status, + "task_id": task_id, + "task_name": task_name, + }, + ai_task_list_params.AITaskListParams, + ), + ), + model=AITask, + ) + + def cancel( + self, + task_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AITaskCancelResponse: + """ + Stopping a previously launched AI-task without waiting for it to be fully + completed. + + The task will be moved to "REVOKED" status. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not task_id: + raise ValueError(f"Expected a non-empty value for `task_id` but received {task_id!r}") + return self._post( + f"/streaming/ai/tasks/{task_id}/cancel", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AITaskCancelResponse, + ) + + def get( + self, + task_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AITaskGetResponse: + """ + This is the single method to check the execution status of an AI task, and + obtain the result of any type of AI task. + + Based on the results of processing, the “result” field will contain an answer + corresponding to the type of the initially created task: + + - ASR: Transcribe video + - ASR: Translate subtitles + - CM: Sports detection + - CM: Not Safe For Work (NSFW) content detection + - CM: Soft nudity detection + - CM: Hard nudity detection + - CM: Objects recognition (soon) + - etc... (see other methods from /ai/ domain) + + A queue is used to process videos. The waiting time depends on the total number + of requests in the system, so sometimes you will have to wait. + + Statuses: + + - PENDING – the task is received and it is pending for available resources + - STARTED – processing has started + - SUCCESS – processing has completed successfully + - FAILURE – processing failed + - REVOKED – processing was cancelled by the user (or the system) + - RETRY – the task execution failed due to internal reasons, the task is queued + for re-execution (up to 3 times) + + Each task is processed in sub-stages, for example, original language is first + determined in a video, and then transcription is performed. In such cases, the + video processing status may change from "STARTED" to "PENDING", and back. This + is due to waiting for resources for a specific processing sub-stage. In this + case, the overall percentage "progress" of video processing will reflect the + full picture. + + The result data is stored for 1 month, after which it is deleted. + + For billing conditions see the corresponding methods in /ai/ domain. The task is + billed only after successful completion of the task and transition to "SUCCESS" + status. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not task_id: + raise ValueError(f"Expected a non-empty value for `task_id` but received {task_id!r}") + return self._get( + f"/streaming/ai/tasks/{task_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AITaskGetResponse, + ) + + def get_ai_settings( + self, + *, + type: Literal["language_support"], + audio_language: str | Omit = omit, + subtitles_language: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AITaskGetAISettingsResponse: + """ + The method for revealing basic information and advanced underlying settings that + are used when performing AI-tasks. + + Parameter sections: + + - "language_support" – AI Translation: check if a language pair is supported or + not for AI translation. + - this list will expand as new AI methods are added. + + **`language_support`** + + There are many languages available for transcription. But not all languages can + be automatically translated to and from with good quality. In order to determine + the availability of translation from the audio language to the desired subtitle + language, you can use this type of "language_support". + + AI models are constantly improving, so this method can be used for dynamic + determination. + + Example: + + ``` + curl -L 'https://api.gcore.com/streaming/ai/info?type=language_support&audio_language=eng&subtitles_language=fre' + + { "supported": true } + ``` + + Today we provide the following capabilities as below. + + These are the 100 languages for which we support only transcription and + translation to English. The iso639-2b codes for these are: + `afr, sqi, amh, ara, hye, asm, aze, bak, eus, bel, ben, bos, bre, bul, mya, cat, zho, hrv, ces, dan, nld, eng, est, fao, fin, fra, glg, kat, deu, guj, hat, hau, haw, heb, hin, hun, isl, ind, ita, jpn, jav, kan, kaz, khm, kor, lao, lat, lav, lin, lit, ltz, mkd, mlg, msa, mal, mlt, mri, mar, ell, mon, nep, nor, nno, oci, pan, fas, pol, por, pus, ron, rus, san, srp, sna, snd, sin, slk, slv, som, spa, sun, swa, swe, tgl, tgk, tam, tat, tel, tha, bod, tur, tuk, ukr, urd, uzb, vie, cym, yid, yor`. + + These are the 77 languages for which we support translation to other languages + and translation to: + `afr, amh, ara, hye, asm, aze, eus, bel, ben, bos, bul, mya, cat, zho, hrv, ces, dan, nld, eng, est, fin, fra, glg, kat, deu, guj, heb, hin, hun, isl, ind, ita, jpn, jav, kan, kaz, khm, kor, lao, lav, lit, mkd, mal, mlt, mar, ell, mon, nep, nno, pan, fas, pol, por, pus, ron, rus, srp, sna, snd, slk, slv, som, spa, swa, swe, tgl, tgk, tam, tel, tha, tur, ukr, urd, vie, cym, yor`. + + Args: + type: The parameters section for which parameters are requested + + audio_language: The source language from which the audio will be transcribed. Required when + `type=language_support`. Value is 3-letter language code according to ISO-639-2 + (bibliographic code), (e.g., fre for French). + + subtitles_language: The target language the text will be translated into. If omitted, the API will + return whether the `audio_language` is supported for transcription only, instead + of translation. Value is 3-letter language code according to ISO-639-2 + (bibliographic code), (e.g., fre for French). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/ai/info", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "type": type, + "audio_language": audio_language, + "subtitles_language": subtitles_language, + }, + ai_task_get_ai_settings_params.AITaskGetAISettingsParams, + ), + ), + cast_to=AITaskGetAISettingsResponse, + ) + + +class AsyncAITasksResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAITasksResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncAITasksResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAITasksResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncAITasksResourceWithStreamingResponse(self) + + async def create( + self, + *, + task_name: Literal["transcription", "content-moderation"], + url: str, + audio_language: str | Omit = omit, + category: Literal["sport", "nsfw", "hard_nudity", "soft_nudity"] | Omit = omit, + client_entity_data: str | Omit = omit, + client_user_id: str | Omit = omit, + subtitles_language: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AITaskCreateResponse: + """ + Creating an AI task. + + This method allows you to create an AI task for VOD video processing: + + - ASR: Transcribe video + - ASR: Translate subtitles + - CM: Sports detection + - CM: Not Safe For Work (NSFW) content detection + - CM: Soft nudity detection + - CM: Hard nudity detection + - CM: Objects recognition (soon) + + ![Auto generated subtitles example](https://demo-files.gvideo.io/apidocs/captions.gif) + + How to use: + + - Create an AI task, specify algoritm to use + - Get `task_id` + - Check a result using `.../ai/tasks/{task_id}` method + + For more detailed information, see the description of each method separately. + + **AI Automatic Speech Recognition (ASR)** + + AI is instrumental in automatic video processing for subtitles creation by using + Automatic Speech Recognition (ASR) technology to transcribe spoken words into + text, which can then be translated into multiple languages for broader + accessibility. + + Categories: + + - `transcription` – to create subtitles/captions from audio in the original + language. + - `translation` – to transate subtitles/captions from the original language to + 99+ other languages. + + AI subtitle transcription and translation tools are highly efficient, processing + large volumes of audio-visual content quickly and providing accurate + transcriptions and translations with minimal human intervention. Additionally, + AI-driven solutions can significantly reduce costs and turnaround times compared + to traditional methods, making them an invaluable resource for content creators + and broadcasters aiming to reach global audiences. + + Example response with positive result: + + ``` + { + "status": "SUCCESS", + "result": { + "subtitles": [ + { + "start_time": "00:00:00.031", + "end_time": "00:00:03.831", + "text": "Come on team, ..." + }, ... + ] + "vttContent": "WEBVTT\n\n1\n00:00:00.031 --> 00:00:03.831\nCome on team, ...", + "concatenated_text": "Come on team, ...", + "languages": [ "eng" ], + "speech_detected": true + } + }, ... + } + ``` + + **AI Content Moderation (CM)** + + The AI Content Moderation API offers a powerful solution for analyzing video + content to detect various categories of inappropriate material. Leveraging + state-of-the-art AI models, this API ensures real-time analysis and flagging of + sensitive or restricted content types, making it an essential tool for platforms + requiring stringent content moderation. + + Categories: + + - `nsfw`: Quick algorithm to detect pornographic material, ensuring content is + "not-safe-for-work" or normal. + - `hard_nudity`: Detailed analisys of video which detects explicit nudity + involving genitalia. + - `soft_nudity`: Detailed video analysis that reveals both explicit and partial + nudity, including the presence of male and female faces and other uncovered + body parts. + - `sport`: Recognizes various sporting activities. + + The AI Content Moderation API is an invaluable tool for managing and controlling + the type of content being shared or streamed on your platform. By implementing + this API, you can ensure compliance with community guidelines and legal + requirements, as well as provide a safer environment for your users. + + Important notes: + + - It's allowed to analyse still images too (where applicable). Format of image: + JPEG, PNG. In that case one image is the same as video of 1 second duration. + - Not all frames in the video are used for analysis, but only key frames + (Iframe). For example, if a key frame in a video is set every ±2 seconds, then + detection will only occur at these timestamps. If an object appears and + disappears between these time stamps, it will not be detected. We are working + on a version to analyze more frames, please contact your manager or our + support team to enable this method. + + Example response with positive result: + + ``` + { + "status": "SUCCESS", + "result": { + "nsfw_detected": true, + "detection_results": ["nsfw"], + "frames": [{"label": "nsfw", "confidence": 1.0, "frame_number": 24}, ...], + }, + } + ``` + + **Additional information** + + Billing takes into account the duration of the analyzed video. Or the duration + until the stop tag(where applicable), if the condition was triggered during the + analysis. + + The heart of content moderation is AI, with additional services. They run on our + own infrastructure, so the files/data are not transferred anywhere to external + services. After processing, original files are also deleted from local storage + of AI. + + Read more detailed information about our solution, and architecture, and + benefits in the knowledge base and blog. + + Args: + task_name: Name of the task to be performed + + url: URL to the MP4 file to analyse. File must be publicly accessible via HTTP/HTTPS. + + audio_language: Language in original audio (transcription only). This value is used to determine + the language from which to transcribe. + + If this is not set, the system will run auto language identification and the + subtitles will be in the detected language. The method also works based on AI + analysis. It's fairly accurate, but if it's wrong, then set the language + explicitly. + + Additionally, when this is not set, we also support recognition of alternate + languages in the video (language code-switching). + + Language is set by 3-letter language code according to ISO-639-2 (bibliographic + code). + + We can process languages: + + - 'afr': Afrikaans + - 'alb': Albanian + - 'amh': Amharic + - 'ara': Arabic + - 'arm': Armenian + - 'asm': Assamese + - 'aze': Azerbaijani + - 'bak': Bashkir + - 'baq': Basque + - 'bel': Belarusian + - 'ben': Bengali + - 'bos': Bosnian + - 'bre': Breton + - 'bul': Bulgarian + - 'bur': Myanmar + - 'cat': Catalan + - 'chi': Chinese + - 'cze': Czech + - 'dan': Danish + - 'dut': Nynorsk + - 'eng': English + - 'est': Estonian + - 'fao': Faroese + - 'fin': Finnish + - 'fre': French + - 'geo': Georgian + - 'ger': German + - 'glg': Galician + - 'gre': Greek + - 'guj': Gujarati + - 'hat': Haitian creole + - 'hau': Hausa + - 'haw': Hawaiian + - 'heb': Hebrew + - 'hin': Hindi + - 'hrv': Croatian + - 'hun': Hungarian + - 'ice': Icelandic + - 'ind': Indonesian + - 'ita': Italian + - 'jav': Javanese + - 'jpn': Japanese + - 'kan': Kannada + - 'kaz': Kazakh + - 'khm': Khmer + - 'kor': Korean + - 'lao': Lao + - 'lat': Latin + - 'lav': Latvian + - 'lin': Lingala + - 'lit': Lithuanian + - 'ltz': Luxembourgish + - 'mac': Macedonian + - 'mal': Malayalam + - 'mao': Maori + - 'mar': Marathi + - 'may': Malay + - 'mlg': Malagasy + - 'mlt': Maltese + - 'mon': Mongolian + - 'nep': Nepali + - 'dut': Dutch + - 'nor': Norwegian + - 'oci': Occitan + - 'pan': Punjabi + - 'per': Persian + - 'pol': Polish + - 'por': Portuguese + - 'pus': Pashto + - 'rum': Romanian + - 'rus': Russian + - 'san': Sanskrit + - 'sin': Sinhala + - 'slo': Slovak + - 'slv': Slovenian + - 'sna': Shona + - 'snd': Sindhi + - 'som': Somali + - 'spa': Spanish + - 'srp': Serbian + - 'sun': Sundanese + - 'swa': Swahili + - 'swe': Swedish + - 'tam': Tamil + - 'tat': Tatar + - 'tel': Telugu + - 'tgk': Tajik + - 'tgl': Tagalog + - 'tha': Thai + - 'tib': Tibetan + - 'tuk': Turkmen + - 'tur': Turkish + - 'ukr': Ukrainian + - 'urd': Urdu + - 'uzb': Uzbek + - 'vie': Vietnamese + - 'wel': Welsh + - 'yid': Yiddish + - 'yor': Yoruba + + category: Model for analysis (content-moderation only). Determines what exactly needs to + be found in the video. + + client_entity_data: Meta parameter, designed to store your own extra information about a video + entity: video source, video id, etc. It is not used in any way in video + processing. + + For example, if an AI-task was created automatically when you uploaded a video + with the AI auto-processing option (nudity detection, etc), then the ID of the + associated video for which the task was performed will be explicitly indicated + here. + + client_user_id: Meta parameter, designed to store your own identifier. Can be used by you to tag + requests from different end-users. It is not used in any way in video + processing. + + subtitles_language: Indicates which language it is clearly necessary to translate into. If this is + not set, the original language will be used from attribute "audio_language". + + Please note that: + + - transcription into the original language is a free procedure, + - and translation from the original language into any other languages is a + "translation" procedure and is paid. More details in + [POST /streaming/ai/tasks#transcribe](/docs/api-reference/streaming/ai/create-ai-asr-task). + Language is set by 3-letter language code according to ISO-639-2 + (bibliographic code). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/streaming/ai/tasks", + body=await async_maybe_transform( + { + "task_name": task_name, + "url": url, + "audio_language": audio_language, + "category": category, + "client_entity_data": client_entity_data, + "client_user_id": client_user_id, + "subtitles_language": subtitles_language, + }, + ai_task_create_params.AITaskCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AITaskCreateResponse, + ) + + def list( + self, + *, + date_created: str | Omit = omit, + limit: int | Omit = omit, + ordering: Literal["task_id", "status", "task_name", "started_at"] | Omit = omit, + page: int | Omit = omit, + search: str | Omit = omit, + status: Literal["FAILURE", "PENDING", "RECEIVED", "RETRY", "REVOKED", "STARTED", "SUCCESS"] | Omit = omit, + task_id: str | Omit = omit, + task_name: Literal["transcription", "content-moderation"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[AITask, AsyncPageStreamingAI[AITask]]: + """ + Returns a list of previously created and processed AI tasks. + + The list contains brief information about the task and its execution status. + Data is displayed page by page. + + Args: + date_created: Time when task was created. Datetime in ISO 8601 format. + + limit: Number of results to return per page. + + ordering: Which field to use when ordering the results: `task_id`, status, and + `task_name`. Sorting is done in ascending (ASC) order. + + If parameter is omitted then "started_at DESC" is used for ordering by default. + + page: Page to view from task list, starting from 1 + + search: This is an field for combined text search in the following fields: `task_id`, + `task_name`, status, and `task_data`. + + Both full and partial searches are possible inside specified above fields. For + example, you can filter tasks of a certain category, or tasks by a specific + original file. + + Example: + + - To filter tasks of Content Moderation NSFW method: + `GET /streaming/ai/tasks?search=nsfw` + - To filter tasks of processing video from a specific origin: + `GET /streaming/ai/tasks?search=s3.eu-west-1.amazonaws.com` + + status: Task status + + task_id: The task unique identifier to fiund + + task_name: Type of the AI task. Reflects the original API method that was used to create + the AI task. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/ai/tasks", + page=AsyncPageStreamingAI[AITask], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_created": date_created, + "limit": limit, + "ordering": ordering, + "page": page, + "search": search, + "status": status, + "task_id": task_id, + "task_name": task_name, + }, + ai_task_list_params.AITaskListParams, + ), + ), + model=AITask, + ) + + async def cancel( + self, + task_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AITaskCancelResponse: + """ + Stopping a previously launched AI-task without waiting for it to be fully + completed. + + The task will be moved to "REVOKED" status. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not task_id: + raise ValueError(f"Expected a non-empty value for `task_id` but received {task_id!r}") + return await self._post( + f"/streaming/ai/tasks/{task_id}/cancel", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AITaskCancelResponse, + ) + + async def get( + self, + task_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AITaskGetResponse: + """ + This is the single method to check the execution status of an AI task, and + obtain the result of any type of AI task. + + Based on the results of processing, the “result” field will contain an answer + corresponding to the type of the initially created task: + + - ASR: Transcribe video + - ASR: Translate subtitles + - CM: Sports detection + - CM: Not Safe For Work (NSFW) content detection + - CM: Soft nudity detection + - CM: Hard nudity detection + - CM: Objects recognition (soon) + - etc... (see other methods from /ai/ domain) + + A queue is used to process videos. The waiting time depends on the total number + of requests in the system, so sometimes you will have to wait. + + Statuses: + + - PENDING – the task is received and it is pending for available resources + - STARTED – processing has started + - SUCCESS – processing has completed successfully + - FAILURE – processing failed + - REVOKED – processing was cancelled by the user (or the system) + - RETRY – the task execution failed due to internal reasons, the task is queued + for re-execution (up to 3 times) + + Each task is processed in sub-stages, for example, original language is first + determined in a video, and then transcription is performed. In such cases, the + video processing status may change from "STARTED" to "PENDING", and back. This + is due to waiting for resources for a specific processing sub-stage. In this + case, the overall percentage "progress" of video processing will reflect the + full picture. + + The result data is stored for 1 month, after which it is deleted. + + For billing conditions see the corresponding methods in /ai/ domain. The task is + billed only after successful completion of the task and transition to "SUCCESS" + status. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not task_id: + raise ValueError(f"Expected a non-empty value for `task_id` but received {task_id!r}") + return await self._get( + f"/streaming/ai/tasks/{task_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AITaskGetResponse, + ) + + async def get_ai_settings( + self, + *, + type: Literal["language_support"], + audio_language: str | Omit = omit, + subtitles_language: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AITaskGetAISettingsResponse: + """ + The method for revealing basic information and advanced underlying settings that + are used when performing AI-tasks. + + Parameter sections: + + - "language_support" – AI Translation: check if a language pair is supported or + not for AI translation. + - this list will expand as new AI methods are added. + + **`language_support`** + + There are many languages available for transcription. But not all languages can + be automatically translated to and from with good quality. In order to determine + the availability of translation from the audio language to the desired subtitle + language, you can use this type of "language_support". + + AI models are constantly improving, so this method can be used for dynamic + determination. + + Example: + + ``` + curl -L 'https://api.gcore.com/streaming/ai/info?type=language_support&audio_language=eng&subtitles_language=fre' + + { "supported": true } + ``` + + Today we provide the following capabilities as below. + + These are the 100 languages for which we support only transcription and + translation to English. The iso639-2b codes for these are: + `afr, sqi, amh, ara, hye, asm, aze, bak, eus, bel, ben, bos, bre, bul, mya, cat, zho, hrv, ces, dan, nld, eng, est, fao, fin, fra, glg, kat, deu, guj, hat, hau, haw, heb, hin, hun, isl, ind, ita, jpn, jav, kan, kaz, khm, kor, lao, lat, lav, lin, lit, ltz, mkd, mlg, msa, mal, mlt, mri, mar, ell, mon, nep, nor, nno, oci, pan, fas, pol, por, pus, ron, rus, san, srp, sna, snd, sin, slk, slv, som, spa, sun, swa, swe, tgl, tgk, tam, tat, tel, tha, bod, tur, tuk, ukr, urd, uzb, vie, cym, yid, yor`. + + These are the 77 languages for which we support translation to other languages + and translation to: + `afr, amh, ara, hye, asm, aze, eus, bel, ben, bos, bul, mya, cat, zho, hrv, ces, dan, nld, eng, est, fin, fra, glg, kat, deu, guj, heb, hin, hun, isl, ind, ita, jpn, jav, kan, kaz, khm, kor, lao, lav, lit, mkd, mal, mlt, mar, ell, mon, nep, nno, pan, fas, pol, por, pus, ron, rus, srp, sna, snd, slk, slv, som, spa, swa, swe, tgl, tgk, tam, tel, tha, tur, ukr, urd, vie, cym, yor`. + + Args: + type: The parameters section for which parameters are requested + + audio_language: The source language from which the audio will be transcribed. Required when + `type=language_support`. Value is 3-letter language code according to ISO-639-2 + (bibliographic code), (e.g., fre for French). + + subtitles_language: The target language the text will be translated into. If omitted, the API will + return whether the `audio_language` is supported for transcription only, instead + of translation. Value is 3-letter language code according to ISO-639-2 + (bibliographic code), (e.g., fre for French). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/ai/info", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "type": type, + "audio_language": audio_language, + "subtitles_language": subtitles_language, + }, + ai_task_get_ai_settings_params.AITaskGetAISettingsParams, + ), + ), + cast_to=AITaskGetAISettingsResponse, + ) + + +class AITasksResourceWithRawResponse: + def __init__(self, ai_tasks: AITasksResource) -> None: + self._ai_tasks = ai_tasks + + self.create = to_raw_response_wrapper( + ai_tasks.create, + ) + self.list = to_raw_response_wrapper( + ai_tasks.list, + ) + self.cancel = to_raw_response_wrapper( + ai_tasks.cancel, + ) + self.get = to_raw_response_wrapper( + ai_tasks.get, + ) + self.get_ai_settings = to_raw_response_wrapper( + ai_tasks.get_ai_settings, + ) + + +class AsyncAITasksResourceWithRawResponse: + def __init__(self, ai_tasks: AsyncAITasksResource) -> None: + self._ai_tasks = ai_tasks + + self.create = async_to_raw_response_wrapper( + ai_tasks.create, + ) + self.list = async_to_raw_response_wrapper( + ai_tasks.list, + ) + self.cancel = async_to_raw_response_wrapper( + ai_tasks.cancel, + ) + self.get = async_to_raw_response_wrapper( + ai_tasks.get, + ) + self.get_ai_settings = async_to_raw_response_wrapper( + ai_tasks.get_ai_settings, + ) + + +class AITasksResourceWithStreamingResponse: + def __init__(self, ai_tasks: AITasksResource) -> None: + self._ai_tasks = ai_tasks + + self.create = to_streamed_response_wrapper( + ai_tasks.create, + ) + self.list = to_streamed_response_wrapper( + ai_tasks.list, + ) + self.cancel = to_streamed_response_wrapper( + ai_tasks.cancel, + ) + self.get = to_streamed_response_wrapper( + ai_tasks.get, + ) + self.get_ai_settings = to_streamed_response_wrapper( + ai_tasks.get_ai_settings, + ) + + +class AsyncAITasksResourceWithStreamingResponse: + def __init__(self, ai_tasks: AsyncAITasksResource) -> None: + self._ai_tasks = ai_tasks + + self.create = async_to_streamed_response_wrapper( + ai_tasks.create, + ) + self.list = async_to_streamed_response_wrapper( + ai_tasks.list, + ) + self.cancel = async_to_streamed_response_wrapper( + ai_tasks.cancel, + ) + self.get = async_to_streamed_response_wrapper( + ai_tasks.get, + ) + self.get_ai_settings = async_to_streamed_response_wrapper( + ai_tasks.get_ai_settings, + ) diff --git a/src/gcore/resources/streaming/api.md b/src/gcore/resources/streaming/api.md new file mode 100644 index 00000000..1e868475 --- /dev/null +++ b/src/gcore/resources/streaming/api.md @@ -0,0 +1,285 @@ +# Streaming + +Types: + +```python +from gcore.types.streaming import CreateVideo, Video +``` + +## AITasks + +Types: + +```python +from gcore.types.streaming import ( + AIContentmoderationHardnudity, + AIContentmoderationNsfw, + AIContentmoderationSoftnudity, + AIContentmoderationSport, + AITask, + AITaskCreateResponse, + AITaskCancelResponse, + AITaskGetResponse, + AITaskGetAISettingsResponse, +) +``` + +Methods: + +- client.streaming.ai_tasks.create(\*\*params) -> AITaskCreateResponse +- client.streaming.ai_tasks.list(\*\*params) -> SyncPageStreamingAI[AITask] +- client.streaming.ai_tasks.cancel(task_id) -> AITaskCancelResponse +- client.streaming.ai_tasks.get(task_id) -> AITaskGetResponse +- client.streaming.ai_tasks.get_ai_settings(\*\*params) -> AITaskGetAISettingsResponse + +## Broadcasts + +Types: + +```python +from gcore.types.streaming import Broadcast, BroadcastSpectatorsCount +``` + +Methods: + +- client.streaming.broadcasts.create(\*\*params) -> None +- client.streaming.broadcasts.update(broadcast_id, \*\*params) -> Broadcast +- client.streaming.broadcasts.list(\*\*params) -> SyncPageStreaming[Broadcast] +- client.streaming.broadcasts.delete(broadcast_id) -> None +- client.streaming.broadcasts.get(broadcast_id) -> Broadcast +- client.streaming.broadcasts.get_spectators_count(broadcast_id) -> BroadcastSpectatorsCount + +## Directories + +Types: + +```python +from gcore.types.streaming import ( + DirectoriesTree, + DirectoryBase, + DirectoryItem, + DirectoryVideo, + DirectoryGetResponse, +) +``` + +Methods: + +- client.streaming.directories.create(\*\*params) -> DirectoryBase +- client.streaming.directories.update(directory_id, \*\*params) -> DirectoryBase +- client.streaming.directories.delete(directory_id) -> None +- client.streaming.directories.get(directory_id) -> DirectoryGetResponse +- client.streaming.directories.get_tree() -> DirectoriesTree + +## Players + +Types: + +```python +from gcore.types.streaming import Player +``` + +Methods: + +- client.streaming.players.create(\*\*params) -> None +- client.streaming.players.update(player_id, \*\*params) -> Player +- client.streaming.players.list(\*\*params) -> SyncPageStreaming[Player] +- client.streaming.players.delete(player_id) -> None +- client.streaming.players.get(player_id) -> Player +- client.streaming.players.preview(player_id) -> None + +## QualitySets + +Types: + +```python +from gcore.types.streaming import QualitySets +``` + +Methods: + +- client.streaming.quality_sets.list() -> QualitySets +- client.streaming.quality_sets.set_default(\*\*params) -> QualitySets + +## Playlists + +Types: + +```python +from gcore.types.streaming import ( + Playlist, + PlaylistCreated, + PlaylistVideo, + PlaylistListVideosResponse, +) +``` + +Methods: + +- client.streaming.playlists.create(\*\*params) -> PlaylistCreated +- client.streaming.playlists.update(playlist_id, \*\*params) -> Playlist +- client.streaming.playlists.list(\*\*params) -> SyncPageStreaming[Playlist] +- client.streaming.playlists.delete(playlist_id) -> None +- client.streaming.playlists.get(playlist_id) -> Playlist +- client.streaming.playlists.list_videos(playlist_id) -> PlaylistListVideosResponse + +## Videos + +Types: + +```python +from gcore.types.streaming import ( + DirectUploadParameters, + Subtitle, + SubtitleBase, + SubtitleBody, + SubtitleUpdated, + VideoCreateResponse, + VideoCreateMultipleResponse, +) +``` + +Methods: + +- client.streaming.videos.create(\*\*params) -> VideoCreateResponse +- client.streaming.videos.update(video_id, \*\*params) -> Video +- client.streaming.videos.list(\*\*params) -> SyncPageStreaming[Video] +- client.streaming.videos.delete(video_id) -> None +- client.streaming.videos.create_multiple(\*\*params) -> VideoCreateMultipleResponse +- client.streaming.videos.get(video_id) -> Video +- client.streaming.videos.get_parameters_for_direct_upload(video_id) -> DirectUploadParameters +- client.streaming.videos.list_names(\*\*params) -> None + +### Subtitles + +Types: + +```python +from gcore.types.streaming.videos import SubtitleListResponse +``` + +Methods: + +- client.streaming.videos.subtitles.create(video_id, \*\*params) -> Subtitle +- client.streaming.videos.subtitles.update(id, \*, video_id, \*\*params) -> SubtitleBase +- client.streaming.videos.subtitles.list(video_id) -> SubtitleListResponse +- client.streaming.videos.subtitles.delete(id, \*, video_id) -> None +- client.streaming.videos.subtitles.get(id, \*, video_id) -> Subtitle + +## Streams + +Types: + +```python +from gcore.types.streaming import ( + Clip, + Stream, + StreamListClipsResponse, + StreamStartRecordingResponse, +) +``` + +Methods: + +- client.streaming.streams.create(\*\*params) -> Stream +- client.streaming.streams.update(stream_id, \*\*params) -> Stream +- client.streaming.streams.list(\*\*params) -> SyncPageStreaming[Stream] +- client.streaming.streams.delete(stream_id) -> None +- client.streaming.streams.clear_dvr(stream_id) -> None +- client.streaming.streams.create_clip(stream_id, \*\*params) -> Clip +- client.streaming.streams.get(stream_id) -> Stream +- client.streaming.streams.list_clips(stream_id) -> StreamListClipsResponse +- client.streaming.streams.start_recording(stream_id) -> StreamStartRecordingResponse +- client.streaming.streams.stop_recording(stream_id) -> Video + +### Overlays + +Types: + +```python +from gcore.types.streaming.streams import ( + Overlay, + OverlayCreateResponse, + OverlayListResponse, + OverlayUpdateMultipleResponse, +) +``` + +Methods: + +- client.streaming.streams.overlays.create(stream_id, \*\*params) -> OverlayCreateResponse +- client.streaming.streams.overlays.update(overlay_id, \*, stream_id, \*\*params) -> Overlay +- client.streaming.streams.overlays.list(stream_id) -> OverlayListResponse +- client.streaming.streams.overlays.delete(overlay_id, \*, stream_id) -> None +- client.streaming.streams.overlays.get(overlay_id, \*, stream_id) -> Overlay +- client.streaming.streams.overlays.update_multiple(stream_id, \*\*params) -> OverlayUpdateMultipleResponse + +## Restreams + +Types: + +```python +from gcore.types.streaming import Restream +``` + +Methods: + +- client.streaming.restreams.create(\*\*params) -> None +- client.streaming.restreams.update(restream_id, \*\*params) -> Restream +- client.streaming.restreams.list(\*\*params) -> SyncPageStreaming[Restream] +- client.streaming.restreams.delete(restream_id) -> None +- client.streaming.restreams.get(restream_id) -> Restream + +## Statistics + +Types: + +```python +from gcore.types.streaming import ( + Ffprobes, + MaxStreamSeries, + PopularVideos, + StorageSeries, + StreamSeries, + UniqueViewers, + UniqueViewersCDN, + Views, + ViewsByBrowser, + ViewsByCountry, + ViewsByHostname, + ViewsByOperatingSystem, + ViewsByReferer, + ViewsByRegion, + ViewsHeatmap, + VodStatisticsSeries, + VodTotalStreamDurationSeries, + StatisticGetLiveUniqueViewersResponse, + StatisticGetVodWatchTimeTotalCDNResponse, +) +``` + +Methods: + +- client.streaming.statistics.get_ffprobes(\*\*params) -> Ffprobes +- client.streaming.statistics.get_live_unique_viewers(\*\*params) -> StatisticGetLiveUniqueViewersResponse +- client.streaming.statistics.get_live_watch_time_cdn(\*\*params) -> StreamSeries +- client.streaming.statistics.get_live_watch_time_total_cdn(\*\*params) -> VodTotalStreamDurationSeries +- client.streaming.statistics.get_max_streams_series(\*\*params) -> MaxStreamSeries +- client.streaming.statistics.get_popular_videos(\*\*params) -> PopularVideos +- client.streaming.statistics.get_storage_series(\*\*params) -> StorageSeries +- client.streaming.statistics.get_stream_series(\*\*params) -> StreamSeries +- client.streaming.statistics.get_unique_viewers(\*\*params) -> UniqueViewers +- client.streaming.statistics.get_unique_viewers_cdn(\*\*params) -> UniqueViewersCDN +- client.streaming.statistics.get_views(\*\*params) -> Views +- client.streaming.statistics.get_views_by_browsers(\*\*params) -> ViewsByBrowser +- client.streaming.statistics.get_views_by_country(\*\*params) -> ViewsByCountry +- client.streaming.statistics.get_views_by_hostname(\*\*params) -> ViewsByHostname +- client.streaming.statistics.get_views_by_operating_system(\*\*params) -> ViewsByOperatingSystem +- client.streaming.statistics.get_views_by_referer(\*\*params) -> ViewsByReferer +- client.streaming.statistics.get_views_by_region(\*\*params) -> ViewsByRegion +- client.streaming.statistics.get_views_heatmap(\*\*params) -> ViewsHeatmap +- client.streaming.statistics.get_vod_storage_volume(\*\*params) -> VodStatisticsSeries +- client.streaming.statistics.get_vod_transcoding_duration(\*\*params) -> VodStatisticsSeries +- client.streaming.statistics.get_vod_unique_viewers_cdn(\*\*params) -> VodStatisticsSeries +- client.streaming.statistics.get_vod_watch_time_cdn(\*\*params) -> VodStatisticsSeries +- client.streaming.statistics.get_vod_watch_time_total_cdn(\*\*params) -> StatisticGetVodWatchTimeTotalCDNResponse diff --git a/src/gcore/resources/streaming/broadcasts.py b/src/gcore/resources/streaming/broadcasts.py new file mode 100644 index 00000000..757bde4d --- /dev/null +++ b/src/gcore/resources/streaming/broadcasts.py @@ -0,0 +1,583 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncPageStreaming, AsyncPageStreaming +from ..._base_client import AsyncPaginator, make_request_options +from ...types.streaming import broadcast_list_params, broadcast_create_params, broadcast_update_params +from ...types.streaming.broadcast import Broadcast +from ...types.streaming.broadcast_spectators_count import BroadcastSpectatorsCount + +__all__ = ["BroadcastsResource", "AsyncBroadcastsResource"] + + +class BroadcastsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> BroadcastsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return BroadcastsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BroadcastsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return BroadcastsResourceWithStreamingResponse(self) + + def create( + self, + *, + broadcast: broadcast_create_params.Broadcast | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Broadcast entity is for setting up HTML video player, which serves to combine: + + - many live streams, + - advertising, + - and design in one config. + + If you use other players or you get streams by direct .m3u8/.mpd links, then you + will not need this entity. + + Scheme of "broadcast" entity using: + ![Scheme of "broadcast" using](https://demo-files.gvideo.io/apidocs/broadcasts.png) + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + "/streaming/broadcasts", + body=maybe_transform({"broadcast": broadcast}, broadcast_create_params.BroadcastCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def update( + self, + broadcast_id: int, + *, + broadcast: broadcast_update_params.Broadcast | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Broadcast: + """ + Updates broadcast settings + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/streaming/broadcasts/{broadcast_id}", + body=maybe_transform({"broadcast": broadcast}, broadcast_update_params.BroadcastUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Broadcast, + ) + + def list( + self, + *, + page: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncPageStreaming[Broadcast]: + """ + Note: Feature "Broadcast" is outdated, soon it will be replaced by + "Multicamera". + + Returns a list of broadcasts. Please see description in POST method. + + Args: + page: Query parameter. Use it to list the paginated content + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/broadcasts", + page=SyncPageStreaming[Broadcast], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"page": page}, broadcast_list_params.BroadcastListParams), + ), + model=Broadcast, + ) + + def delete( + self, + broadcast_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete broadcast + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/streaming/broadcasts/{broadcast_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + broadcast_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Broadcast: + """ + Returns broadcast details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/broadcasts/{broadcast_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Broadcast, + ) + + def get_spectators_count( + self, + broadcast_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BroadcastSpectatorsCount: + """ + Returns number of simultaneous broadcast viewers at the current moment + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/broadcasts/{broadcast_id}/spectators", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BroadcastSpectatorsCount, + ) + + +class AsyncBroadcastsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncBroadcastsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncBroadcastsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBroadcastsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncBroadcastsResourceWithStreamingResponse(self) + + async def create( + self, + *, + broadcast: broadcast_create_params.Broadcast | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Broadcast entity is for setting up HTML video player, which serves to combine: + + - many live streams, + - advertising, + - and design in one config. + + If you use other players or you get streams by direct .m3u8/.mpd links, then you + will not need this entity. + + Scheme of "broadcast" entity using: + ![Scheme of "broadcast" using](https://demo-files.gvideo.io/apidocs/broadcasts.png) + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + "/streaming/broadcasts", + body=await async_maybe_transform({"broadcast": broadcast}, broadcast_create_params.BroadcastCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def update( + self, + broadcast_id: int, + *, + broadcast: broadcast_update_params.Broadcast | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Broadcast: + """ + Updates broadcast settings + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/streaming/broadcasts/{broadcast_id}", + body=await async_maybe_transform({"broadcast": broadcast}, broadcast_update_params.BroadcastUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Broadcast, + ) + + def list( + self, + *, + page: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Broadcast, AsyncPageStreaming[Broadcast]]: + """ + Note: Feature "Broadcast" is outdated, soon it will be replaced by + "Multicamera". + + Returns a list of broadcasts. Please see description in POST method. + + Args: + page: Query parameter. Use it to list the paginated content + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/broadcasts", + page=AsyncPageStreaming[Broadcast], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"page": page}, broadcast_list_params.BroadcastListParams), + ), + model=Broadcast, + ) + + async def delete( + self, + broadcast_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete broadcast + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/streaming/broadcasts/{broadcast_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + broadcast_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Broadcast: + """ + Returns broadcast details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/broadcasts/{broadcast_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Broadcast, + ) + + async def get_spectators_count( + self, + broadcast_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BroadcastSpectatorsCount: + """ + Returns number of simultaneous broadcast viewers at the current moment + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/broadcasts/{broadcast_id}/spectators", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BroadcastSpectatorsCount, + ) + + +class BroadcastsResourceWithRawResponse: + def __init__(self, broadcasts: BroadcastsResource) -> None: + self._broadcasts = broadcasts + + self.create = to_raw_response_wrapper( + broadcasts.create, + ) + self.update = to_raw_response_wrapper( + broadcasts.update, + ) + self.list = to_raw_response_wrapper( + broadcasts.list, + ) + self.delete = to_raw_response_wrapper( + broadcasts.delete, + ) + self.get = to_raw_response_wrapper( + broadcasts.get, + ) + self.get_spectators_count = to_raw_response_wrapper( + broadcasts.get_spectators_count, + ) + + +class AsyncBroadcastsResourceWithRawResponse: + def __init__(self, broadcasts: AsyncBroadcastsResource) -> None: + self._broadcasts = broadcasts + + self.create = async_to_raw_response_wrapper( + broadcasts.create, + ) + self.update = async_to_raw_response_wrapper( + broadcasts.update, + ) + self.list = async_to_raw_response_wrapper( + broadcasts.list, + ) + self.delete = async_to_raw_response_wrapper( + broadcasts.delete, + ) + self.get = async_to_raw_response_wrapper( + broadcasts.get, + ) + self.get_spectators_count = async_to_raw_response_wrapper( + broadcasts.get_spectators_count, + ) + + +class BroadcastsResourceWithStreamingResponse: + def __init__(self, broadcasts: BroadcastsResource) -> None: + self._broadcasts = broadcasts + + self.create = to_streamed_response_wrapper( + broadcasts.create, + ) + self.update = to_streamed_response_wrapper( + broadcasts.update, + ) + self.list = to_streamed_response_wrapper( + broadcasts.list, + ) + self.delete = to_streamed_response_wrapper( + broadcasts.delete, + ) + self.get = to_streamed_response_wrapper( + broadcasts.get, + ) + self.get_spectators_count = to_streamed_response_wrapper( + broadcasts.get_spectators_count, + ) + + +class AsyncBroadcastsResourceWithStreamingResponse: + def __init__(self, broadcasts: AsyncBroadcastsResource) -> None: + self._broadcasts = broadcasts + + self.create = async_to_streamed_response_wrapper( + broadcasts.create, + ) + self.update = async_to_streamed_response_wrapper( + broadcasts.update, + ) + self.list = async_to_streamed_response_wrapper( + broadcasts.list, + ) + self.delete = async_to_streamed_response_wrapper( + broadcasts.delete, + ) + self.get = async_to_streamed_response_wrapper( + broadcasts.get, + ) + self.get_spectators_count = async_to_streamed_response_wrapper( + broadcasts.get_spectators_count, + ) diff --git a/src/gcore/resources/streaming/directories.py b/src/gcore/resources/streaming/directories.py new file mode 100644 index 00000000..00a379cc --- /dev/null +++ b/src/gcore/resources/streaming/directories.py @@ -0,0 +1,521 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.streaming import directory_create_params, directory_update_params +from ...types.streaming.directory_base import DirectoryBase +from ...types.streaming.directories_tree import DirectoriesTree +from ...types.streaming.directory_get_response import DirectoryGetResponse + +__all__ = ["DirectoriesResource", "AsyncDirectoriesResource"] + + +class DirectoriesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DirectoriesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return DirectoriesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DirectoriesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return DirectoriesResourceWithStreamingResponse(self) + + def create( + self, + *, + name: str, + parent_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DirectoryBase: + """ + Use this method to create a new directory entity. + + Args: + name: Title of the directory. + + parent_id: ID of a parent directory. "null" if it's in the root. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/streaming/directories", + body=maybe_transform( + { + "name": name, + "parent_id": parent_id, + }, + directory_create_params.DirectoryCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DirectoryBase, + ) + + def update( + self, + directory_id: int, + *, + name: str | Omit = omit, + parent_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DirectoryBase: + """ + Change a directory name or move to another "parent_id". + + Args: + name: Title of the directory. Omit this if you don't want to change. + + parent_id: ID of a parent directory. "null" if it's in the root. Omit this if you don't + want to change. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/streaming/directories/{directory_id}", + body=maybe_transform( + { + "name": name, + "parent_id": parent_id, + }, + directory_update_params.DirectoryUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DirectoryBase, + ) + + def delete( + self, + directory_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a directory **and all entities inside**. + + After its execution, all contents of the directory will be deleted recursively: + + - Subdirectories + - Videos + + The directory and contents are deleted permanently and irreversibly. Therefore, + it is impossible to restore files after this. + + For details, see the Product Documentation. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/streaming/directories/{directory_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + directory_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DirectoryGetResponse: + """Complete directory structure with contents. + + The structure contains both + subfolders and videos in a continuous list. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/directories/{directory_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DirectoryGetResponse, + ) + + def get_tree( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DirectoriesTree: + """ + Tree structure of directories. + + This endpoint returns hierarchical data about directories in video hosting. + """ + return self._get( + "/streaming/directories/tree", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DirectoriesTree, + ) + + +class AsyncDirectoriesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDirectoriesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncDirectoriesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDirectoriesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncDirectoriesResourceWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + parent_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DirectoryBase: + """ + Use this method to create a new directory entity. + + Args: + name: Title of the directory. + + parent_id: ID of a parent directory. "null" if it's in the root. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/streaming/directories", + body=await async_maybe_transform( + { + "name": name, + "parent_id": parent_id, + }, + directory_create_params.DirectoryCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DirectoryBase, + ) + + async def update( + self, + directory_id: int, + *, + name: str | Omit = omit, + parent_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DirectoryBase: + """ + Change a directory name or move to another "parent_id". + + Args: + name: Title of the directory. Omit this if you don't want to change. + + parent_id: ID of a parent directory. "null" if it's in the root. Omit this if you don't + want to change. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/streaming/directories/{directory_id}", + body=await async_maybe_transform( + { + "name": name, + "parent_id": parent_id, + }, + directory_update_params.DirectoryUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DirectoryBase, + ) + + async def delete( + self, + directory_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a directory **and all entities inside**. + + After its execution, all contents of the directory will be deleted recursively: + + - Subdirectories + - Videos + + The directory and contents are deleted permanently and irreversibly. Therefore, + it is impossible to restore files after this. + + For details, see the Product Documentation. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/streaming/directories/{directory_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + directory_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DirectoryGetResponse: + """Complete directory structure with contents. + + The structure contains both + subfolders and videos in a continuous list. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/directories/{directory_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DirectoryGetResponse, + ) + + async def get_tree( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DirectoriesTree: + """ + Tree structure of directories. + + This endpoint returns hierarchical data about directories in video hosting. + """ + return await self._get( + "/streaming/directories/tree", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DirectoriesTree, + ) + + +class DirectoriesResourceWithRawResponse: + def __init__(self, directories: DirectoriesResource) -> None: + self._directories = directories + + self.create = to_raw_response_wrapper( + directories.create, + ) + self.update = to_raw_response_wrapper( + directories.update, + ) + self.delete = to_raw_response_wrapper( + directories.delete, + ) + self.get = to_raw_response_wrapper( + directories.get, + ) + self.get_tree = to_raw_response_wrapper( + directories.get_tree, + ) + + +class AsyncDirectoriesResourceWithRawResponse: + def __init__(self, directories: AsyncDirectoriesResource) -> None: + self._directories = directories + + self.create = async_to_raw_response_wrapper( + directories.create, + ) + self.update = async_to_raw_response_wrapper( + directories.update, + ) + self.delete = async_to_raw_response_wrapper( + directories.delete, + ) + self.get = async_to_raw_response_wrapper( + directories.get, + ) + self.get_tree = async_to_raw_response_wrapper( + directories.get_tree, + ) + + +class DirectoriesResourceWithStreamingResponse: + def __init__(self, directories: DirectoriesResource) -> None: + self._directories = directories + + self.create = to_streamed_response_wrapper( + directories.create, + ) + self.update = to_streamed_response_wrapper( + directories.update, + ) + self.delete = to_streamed_response_wrapper( + directories.delete, + ) + self.get = to_streamed_response_wrapper( + directories.get, + ) + self.get_tree = to_streamed_response_wrapper( + directories.get_tree, + ) + + +class AsyncDirectoriesResourceWithStreamingResponse: + def __init__(self, directories: AsyncDirectoriesResource) -> None: + self._directories = directories + + self.create = async_to_streamed_response_wrapper( + directories.create, + ) + self.update = async_to_streamed_response_wrapper( + directories.update, + ) + self.delete = async_to_streamed_response_wrapper( + directories.delete, + ) + self.get = async_to_streamed_response_wrapper( + directories.get, + ) + self.get_tree = async_to_streamed_response_wrapper( + directories.get_tree, + ) diff --git a/src/gcore/resources/streaming/players.py b/src/gcore/resources/streaming/players.py new file mode 100644 index 00000000..b2590c29 --- /dev/null +++ b/src/gcore/resources/streaming/players.py @@ -0,0 +1,577 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncPageStreaming, AsyncPageStreaming +from ..._base_client import AsyncPaginator, make_request_options +from ...types.streaming import Player, player_list_params, player_create_params, player_update_params +from ...types.streaming.player import Player +from ...types.streaming.player_param import PlayerParam + +__all__ = ["PlayersResource", "AsyncPlayersResource"] + + +class PlayersResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> PlayersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return PlayersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PlayersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return PlayersResourceWithStreamingResponse(self) + + def create( + self, + *, + player: PlayerParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Create player + + Args: + player: Set of properties for displaying videos. + + All parameters may be blank to inherit + their values from default Streaming player. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + "/streaming/players", + body=maybe_transform({"player": player}, player_create_params.PlayerCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def update( + self, + player_id: int, + *, + player: PlayerParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Player: + """Updates player settings + + Args: + player: Set of properties for displaying videos. + + All parameters may be blank to inherit + their values from default Streaming player. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/streaming/players/{player_id}", + body=maybe_transform({"player": player}, player_update_params.PlayerUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Player, + ) + + def list( + self, + *, + page: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncPageStreaming[Player]: + """Returns a list of created players + + Args: + page: Query parameter. + + Use it to list the paginated content + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/players", + page=SyncPageStreaming[Player], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"page": page}, player_list_params.PlayerListParams), + ), + model=Player, + ) + + def delete( + self, + player_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete player + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/streaming/players/{player_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + player_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Player: + """ + Returns player settings + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/players/{player_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Player, + ) + + def preview( + self, + player_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Returns player configuration in HTML + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._get( + f"/streaming/players/{player_id}/preview", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncPlayersResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncPlayersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncPlayersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPlayersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncPlayersResourceWithStreamingResponse(self) + + async def create( + self, + *, + player: PlayerParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Create player + + Args: + player: Set of properties for displaying videos. + + All parameters may be blank to inherit + their values from default Streaming player. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + "/streaming/players", + body=await async_maybe_transform({"player": player}, player_create_params.PlayerCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def update( + self, + player_id: int, + *, + player: PlayerParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Player: + """Updates player settings + + Args: + player: Set of properties for displaying videos. + + All parameters may be blank to inherit + their values from default Streaming player. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/streaming/players/{player_id}", + body=await async_maybe_transform({"player": player}, player_update_params.PlayerUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Player, + ) + + def list( + self, + *, + page: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Player, AsyncPageStreaming[Player]]: + """Returns a list of created players + + Args: + page: Query parameter. + + Use it to list the paginated content + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/players", + page=AsyncPageStreaming[Player], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"page": page}, player_list_params.PlayerListParams), + ), + model=Player, + ) + + async def delete( + self, + player_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete player + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/streaming/players/{player_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + player_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Player: + """ + Returns player settings + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/players/{player_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Player, + ) + + async def preview( + self, + player_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Returns player configuration in HTML + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._get( + f"/streaming/players/{player_id}/preview", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class PlayersResourceWithRawResponse: + def __init__(self, players: PlayersResource) -> None: + self._players = players + + self.create = to_raw_response_wrapper( + players.create, + ) + self.update = to_raw_response_wrapper( + players.update, + ) + self.list = to_raw_response_wrapper( + players.list, + ) + self.delete = to_raw_response_wrapper( + players.delete, + ) + self.get = to_raw_response_wrapper( + players.get, + ) + self.preview = to_raw_response_wrapper( + players.preview, + ) + + +class AsyncPlayersResourceWithRawResponse: + def __init__(self, players: AsyncPlayersResource) -> None: + self._players = players + + self.create = async_to_raw_response_wrapper( + players.create, + ) + self.update = async_to_raw_response_wrapper( + players.update, + ) + self.list = async_to_raw_response_wrapper( + players.list, + ) + self.delete = async_to_raw_response_wrapper( + players.delete, + ) + self.get = async_to_raw_response_wrapper( + players.get, + ) + self.preview = async_to_raw_response_wrapper( + players.preview, + ) + + +class PlayersResourceWithStreamingResponse: + def __init__(self, players: PlayersResource) -> None: + self._players = players + + self.create = to_streamed_response_wrapper( + players.create, + ) + self.update = to_streamed_response_wrapper( + players.update, + ) + self.list = to_streamed_response_wrapper( + players.list, + ) + self.delete = to_streamed_response_wrapper( + players.delete, + ) + self.get = to_streamed_response_wrapper( + players.get, + ) + self.preview = to_streamed_response_wrapper( + players.preview, + ) + + +class AsyncPlayersResourceWithStreamingResponse: + def __init__(self, players: AsyncPlayersResource) -> None: + self._players = players + + self.create = async_to_streamed_response_wrapper( + players.create, + ) + self.update = async_to_streamed_response_wrapper( + players.update, + ) + self.list = async_to_streamed_response_wrapper( + players.list, + ) + self.delete = async_to_streamed_response_wrapper( + players.delete, + ) + self.get = async_to_streamed_response_wrapper( + players.get, + ) + self.preview = async_to_streamed_response_wrapper( + players.preview, + ) diff --git a/src/gcore/resources/streaming/playlists.py b/src/gcore/resources/streaming/playlists.py new file mode 100644 index 00000000..28f15c1a --- /dev/null +++ b/src/gcore/resources/streaming/playlists.py @@ -0,0 +1,1105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncPageStreaming, AsyncPageStreaming +from ..._base_client import AsyncPaginator, make_request_options +from ...types.streaming import playlist_list_params, playlist_create_params, playlist_update_params +from ...types.streaming.playlist import Playlist +from ...types.streaming.playlist_created import PlaylistCreated +from ...types.streaming.playlist_list_videos_response import PlaylistListVideosResponse + +__all__ = ["PlaylistsResource", "AsyncPlaylistsResource"] + + +class PlaylistsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> PlaylistsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return PlaylistsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PlaylistsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return PlaylistsResourceWithStreamingResponse(self) + + def create( + self, + *, + active: bool | Omit = omit, + ad_id: int | Omit = omit, + client_id: int | Omit = omit, + client_user_id: int | Omit = omit, + countdown: bool | Omit = omit, + hls_cmaf_url: str | Omit = omit, + hls_url: str | Omit = omit, + iframe_url: str | Omit = omit, + loop: bool | Omit = omit, + name: str | Omit = omit, + player_id: int | Omit = omit, + playlist_type: Literal["live", "vod"] | Omit = omit, + start_time: str | Omit = omit, + video_ids: Iterable[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlaylistCreated: + """ + Playlist is a curated collection of video content organized in a sequential + manner. + + This method offers several advantages and features that are typical of live + streaming but with more control over the content. Here's how it works: + + - Playlist always consists only of static VOD videos you previously uploaded to + the system. + - Playlist is always played as a "Live stream" for end-users, so without the + ability to fast forward the stream to the “future”. Manifest will contain + chunks as for live stream too. + - Playlist can be looped endlessly. In this case, all the videos in the list + will be constantly repeated through the list. + - Playlist can be programmed to be played at a specific time in the future. In + that case, before the start time there will be empty manifest. + + You can add new videos to the list, remove unnecessary videos, or change the + order of videos in the list. But please pay attention to when the video list + changes, it is updated instantly on the server. This means that after saving the + changed list, the playlist will be reloaded for all users and it will start + plays from the very first element. + + Maximum video limit = 128 videos in a row. + + Examples of usage: + + - Looped video playback + - Scheduled playback + + **Looped video playback** + + It can be used to simulate TV channel pre-programmed behaviour. + + - Selection: Choose a series of videos, such as TV show episodes, movies, + tutorials, or any other relevant content. + - Order: Arrange the selected videos in the desired sequence, much like setting + a broadcast schedule. + - Looping: Optionally, the playlist can be set to loop, replaying the sequence + once it finishes to maintain a continuous stream. + + Example: + + ``` + active: true + loop: true + name: "Playlist: TV channel 'The world around us' (Programmed broadcast for 24 hours)" + ``` + + **Scheduled playback** + + It can be used to simulate live events such as virtual concerts, webinars, or + any special broadcasts without the logistical challenges of an actual live + stream. + + - Timing: Set specific start time, creating the illusion of a live broadcast + schedule. + - Selection: Choose a video or series of videos to be played at the specified + time. + - No Pauses: Unlike on-demand streaming where users can pause and skip, this + emulated live stream runs continuously, mirroring the constraints of + traditional live broadcasts. + + ``` + active: true + loop: false + name: "Playlist: Webinar 'Onboarding for new employees on working with the corporate portal'" + start_time: "2024-07-01T11:00:00Z" + ``` + + Args: + active: + Enables/Disables playlist. Has two possible values: + + - true – Playlist can be played. + - false – Playlist is disabled. No broadcast while it's desabled. + + ad_id: The advertisement ID that will be inserted into the video + + client_id: Current playlist client ID + + client_user_id: Custom field where you can specify user ID in your system + + countdown: Enables countdown before playlist start with `playlist_type: live` + + hls_cmaf_url: A URL to a master playlist HLS (master-cmaf.m3u8) with CMAF-based chunks. Chunks + are in fMP4 container. + + It is possible to use the same suffix-options as described in the "hls_url" + attribute. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + + hls_url: A URL to a master playlist HLS (master.m3u8) with MPEG TS container. + + This URL is a link to the main manifest. But you can also manually specify + suffix-options that will allow you to change the manifest to your request: + + `/playlists/{client_id}_{playlist_id}/master[-cmaf][-min-N][-max-N][-img][-(h264|hevc|av1)].m3u8` + Please see the details in `hls_url` attribute of /videos/{id} method. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + + iframe_url: A URL to a built-in HTML video player with the video inside. It can be inserted + into an iframe on your website and the video will automatically play in all + browsers. + + The player can be opened or shared via this direct link. Also the video player + can be integrated into your web pages using the Iframe tag. + + Please see the details in `iframe_url` attribute of /videos/{id} method. + + loop: Enables/Disables playlist loop + + name: Playlist name + + player_id: The player ID with which the video will be played + + playlist_type: + Determines whether the playlist: + + - `live` - playlist for live-streaming + - `vod` - playlist is for video on demand access + + start_time: Playlist start time. Playlist won't be available before the specified time. + Datetime in ISO 8601 format. + + video_ids: A list of VOD IDs included in the playlist. Order of videos in a playlist + reflects the order of IDs in the array. + + Maximum video limit = 128. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/streaming/playlists", + body=maybe_transform( + { + "active": active, + "ad_id": ad_id, + "client_id": client_id, + "client_user_id": client_user_id, + "countdown": countdown, + "hls_cmaf_url": hls_cmaf_url, + "hls_url": hls_url, + "iframe_url": iframe_url, + "loop": loop, + "name": name, + "player_id": player_id, + "playlist_type": playlist_type, + "start_time": start_time, + "video_ids": video_ids, + }, + playlist_create_params.PlaylistCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlaylistCreated, + ) + + def update( + self, + playlist_id: int, + *, + active: bool | Omit = omit, + ad_id: int | Omit = omit, + client_id: int | Omit = omit, + client_user_id: int | Omit = omit, + countdown: bool | Omit = omit, + hls_cmaf_url: str | Omit = omit, + hls_url: str | Omit = omit, + iframe_url: str | Omit = omit, + loop: bool | Omit = omit, + name: str | Omit = omit, + player_id: int | Omit = omit, + playlist_type: Literal["live", "vod"] | Omit = omit, + start_time: str | Omit = omit, + video_ids: Iterable[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Playlist: + """Change playlist + + Args: + active: + Enables/Disables playlist. + + Has two possible values: + + - true – Playlist can be played. + - false – Playlist is disabled. No broadcast while it's desabled. + + ad_id: The advertisement ID that will be inserted into the video + + client_id: Current playlist client ID + + client_user_id: Custom field where you can specify user ID in your system + + countdown: Enables countdown before playlist start with `playlist_type: live` + + hls_cmaf_url: A URL to a master playlist HLS (master-cmaf.m3u8) with CMAF-based chunks. Chunks + are in fMP4 container. + + It is possible to use the same suffix-options as described in the "hls_url" + attribute. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + + hls_url: A URL to a master playlist HLS (master.m3u8) with MPEG TS container. + + This URL is a link to the main manifest. But you can also manually specify + suffix-options that will allow you to change the manifest to your request: + + `/playlists/{client_id}_{playlist_id}/master[-cmaf][-min-N][-max-N][-img][-(h264|hevc|av1)].m3u8` + Please see the details in `hls_url` attribute of /videos/{id} method. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + + iframe_url: A URL to a built-in HTML video player with the video inside. It can be inserted + into an iframe on your website and the video will automatically play in all + browsers. + + The player can be opened or shared via this direct link. Also the video player + can be integrated into your web pages using the Iframe tag. + + Please see the details in `iframe_url` attribute of /videos/{id} method. + + loop: Enables/Disables playlist loop + + name: Playlist name + + player_id: The player ID with which the video will be played + + playlist_type: + Determines whether the playlist: + + - `live` - playlist for live-streaming + - `vod` - playlist is for video on demand access + + start_time: Playlist start time. Playlist won't be available before the specified time. + Datetime in ISO 8601 format. + + video_ids: A list of VOD IDs included in the playlist. Order of videos in a playlist + reflects the order of IDs in the array. + + Maximum video limit = 128. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/streaming/playlists/{playlist_id}", + body=maybe_transform( + { + "active": active, + "ad_id": ad_id, + "client_id": client_id, + "client_user_id": client_user_id, + "countdown": countdown, + "hls_cmaf_url": hls_cmaf_url, + "hls_url": hls_url, + "iframe_url": iframe_url, + "loop": loop, + "name": name, + "player_id": player_id, + "playlist_type": playlist_type, + "start_time": start_time, + "video_ids": video_ids, + }, + playlist_update_params.PlaylistUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Playlist, + ) + + def list( + self, + *, + page: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncPageStreaming[Playlist]: + """Returns a list of created playlists + + Args: + page: Query parameter. + + Use it to list the paginated content + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/playlists", + page=SyncPageStreaming[Playlist], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"page": page}, playlist_list_params.PlaylistListParams), + ), + model=Playlist, + ) + + def delete( + self, + playlist_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete playlist + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/streaming/playlists/{playlist_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + playlist_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Playlist: + """ + Returns a playlist details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/playlists/{playlist_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Playlist, + ) + + def list_videos( + self, + playlist_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlaylistListVideosResponse: + """ + Shows ordered array of playlist videos + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/playlists/{playlist_id}/videos", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlaylistListVideosResponse, + ) + + +class AsyncPlaylistsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncPlaylistsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncPlaylistsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPlaylistsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncPlaylistsResourceWithStreamingResponse(self) + + async def create( + self, + *, + active: bool | Omit = omit, + ad_id: int | Omit = omit, + client_id: int | Omit = omit, + client_user_id: int | Omit = omit, + countdown: bool | Omit = omit, + hls_cmaf_url: str | Omit = omit, + hls_url: str | Omit = omit, + iframe_url: str | Omit = omit, + loop: bool | Omit = omit, + name: str | Omit = omit, + player_id: int | Omit = omit, + playlist_type: Literal["live", "vod"] | Omit = omit, + start_time: str | Omit = omit, + video_ids: Iterable[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlaylistCreated: + """ + Playlist is a curated collection of video content organized in a sequential + manner. + + This method offers several advantages and features that are typical of live + streaming but with more control over the content. Here's how it works: + + - Playlist always consists only of static VOD videos you previously uploaded to + the system. + - Playlist is always played as a "Live stream" for end-users, so without the + ability to fast forward the stream to the “future”. Manifest will contain + chunks as for live stream too. + - Playlist can be looped endlessly. In this case, all the videos in the list + will be constantly repeated through the list. + - Playlist can be programmed to be played at a specific time in the future. In + that case, before the start time there will be empty manifest. + + You can add new videos to the list, remove unnecessary videos, or change the + order of videos in the list. But please pay attention to when the video list + changes, it is updated instantly on the server. This means that after saving the + changed list, the playlist will be reloaded for all users and it will start + plays from the very first element. + + Maximum video limit = 128 videos in a row. + + Examples of usage: + + - Looped video playback + - Scheduled playback + + **Looped video playback** + + It can be used to simulate TV channel pre-programmed behaviour. + + - Selection: Choose a series of videos, such as TV show episodes, movies, + tutorials, or any other relevant content. + - Order: Arrange the selected videos in the desired sequence, much like setting + a broadcast schedule. + - Looping: Optionally, the playlist can be set to loop, replaying the sequence + once it finishes to maintain a continuous stream. + + Example: + + ``` + active: true + loop: true + name: "Playlist: TV channel 'The world around us' (Programmed broadcast for 24 hours)" + ``` + + **Scheduled playback** + + It can be used to simulate live events such as virtual concerts, webinars, or + any special broadcasts without the logistical challenges of an actual live + stream. + + - Timing: Set specific start time, creating the illusion of a live broadcast + schedule. + - Selection: Choose a video or series of videos to be played at the specified + time. + - No Pauses: Unlike on-demand streaming where users can pause and skip, this + emulated live stream runs continuously, mirroring the constraints of + traditional live broadcasts. + + ``` + active: true + loop: false + name: "Playlist: Webinar 'Onboarding for new employees on working with the corporate portal'" + start_time: "2024-07-01T11:00:00Z" + ``` + + Args: + active: + Enables/Disables playlist. Has two possible values: + + - true – Playlist can be played. + - false – Playlist is disabled. No broadcast while it's desabled. + + ad_id: The advertisement ID that will be inserted into the video + + client_id: Current playlist client ID + + client_user_id: Custom field where you can specify user ID in your system + + countdown: Enables countdown before playlist start with `playlist_type: live` + + hls_cmaf_url: A URL to a master playlist HLS (master-cmaf.m3u8) with CMAF-based chunks. Chunks + are in fMP4 container. + + It is possible to use the same suffix-options as described in the "hls_url" + attribute. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + + hls_url: A URL to a master playlist HLS (master.m3u8) with MPEG TS container. + + This URL is a link to the main manifest. But you can also manually specify + suffix-options that will allow you to change the manifest to your request: + + `/playlists/{client_id}_{playlist_id}/master[-cmaf][-min-N][-max-N][-img][-(h264|hevc|av1)].m3u8` + Please see the details in `hls_url` attribute of /videos/{id} method. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + + iframe_url: A URL to a built-in HTML video player with the video inside. It can be inserted + into an iframe on your website and the video will automatically play in all + browsers. + + The player can be opened or shared via this direct link. Also the video player + can be integrated into your web pages using the Iframe tag. + + Please see the details in `iframe_url` attribute of /videos/{id} method. + + loop: Enables/Disables playlist loop + + name: Playlist name + + player_id: The player ID with which the video will be played + + playlist_type: + Determines whether the playlist: + + - `live` - playlist for live-streaming + - `vod` - playlist is for video on demand access + + start_time: Playlist start time. Playlist won't be available before the specified time. + Datetime in ISO 8601 format. + + video_ids: A list of VOD IDs included in the playlist. Order of videos in a playlist + reflects the order of IDs in the array. + + Maximum video limit = 128. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/streaming/playlists", + body=await async_maybe_transform( + { + "active": active, + "ad_id": ad_id, + "client_id": client_id, + "client_user_id": client_user_id, + "countdown": countdown, + "hls_cmaf_url": hls_cmaf_url, + "hls_url": hls_url, + "iframe_url": iframe_url, + "loop": loop, + "name": name, + "player_id": player_id, + "playlist_type": playlist_type, + "start_time": start_time, + "video_ids": video_ids, + }, + playlist_create_params.PlaylistCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlaylistCreated, + ) + + async def update( + self, + playlist_id: int, + *, + active: bool | Omit = omit, + ad_id: int | Omit = omit, + client_id: int | Omit = omit, + client_user_id: int | Omit = omit, + countdown: bool | Omit = omit, + hls_cmaf_url: str | Omit = omit, + hls_url: str | Omit = omit, + iframe_url: str | Omit = omit, + loop: bool | Omit = omit, + name: str | Omit = omit, + player_id: int | Omit = omit, + playlist_type: Literal["live", "vod"] | Omit = omit, + start_time: str | Omit = omit, + video_ids: Iterable[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Playlist: + """Change playlist + + Args: + active: + Enables/Disables playlist. + + Has two possible values: + + - true – Playlist can be played. + - false – Playlist is disabled. No broadcast while it's desabled. + + ad_id: The advertisement ID that will be inserted into the video + + client_id: Current playlist client ID + + client_user_id: Custom field where you can specify user ID in your system + + countdown: Enables countdown before playlist start with `playlist_type: live` + + hls_cmaf_url: A URL to a master playlist HLS (master-cmaf.m3u8) with CMAF-based chunks. Chunks + are in fMP4 container. + + It is possible to use the same suffix-options as described in the "hls_url" + attribute. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + + hls_url: A URL to a master playlist HLS (master.m3u8) with MPEG TS container. + + This URL is a link to the main manifest. But you can also manually specify + suffix-options that will allow you to change the manifest to your request: + + `/playlists/{client_id}_{playlist_id}/master[-cmaf][-min-N][-max-N][-img][-(h264|hevc|av1)].m3u8` + Please see the details in `hls_url` attribute of /videos/{id} method. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + + iframe_url: A URL to a built-in HTML video player with the video inside. It can be inserted + into an iframe on your website and the video will automatically play in all + browsers. + + The player can be opened or shared via this direct link. Also the video player + can be integrated into your web pages using the Iframe tag. + + Please see the details in `iframe_url` attribute of /videos/{id} method. + + loop: Enables/Disables playlist loop + + name: Playlist name + + player_id: The player ID with which the video will be played + + playlist_type: + Determines whether the playlist: + + - `live` - playlist for live-streaming + - `vod` - playlist is for video on demand access + + start_time: Playlist start time. Playlist won't be available before the specified time. + Datetime in ISO 8601 format. + + video_ids: A list of VOD IDs included in the playlist. Order of videos in a playlist + reflects the order of IDs in the array. + + Maximum video limit = 128. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/streaming/playlists/{playlist_id}", + body=await async_maybe_transform( + { + "active": active, + "ad_id": ad_id, + "client_id": client_id, + "client_user_id": client_user_id, + "countdown": countdown, + "hls_cmaf_url": hls_cmaf_url, + "hls_url": hls_url, + "iframe_url": iframe_url, + "loop": loop, + "name": name, + "player_id": player_id, + "playlist_type": playlist_type, + "start_time": start_time, + "video_ids": video_ids, + }, + playlist_update_params.PlaylistUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Playlist, + ) + + def list( + self, + *, + page: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Playlist, AsyncPageStreaming[Playlist]]: + """Returns a list of created playlists + + Args: + page: Query parameter. + + Use it to list the paginated content + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/playlists", + page=AsyncPageStreaming[Playlist], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"page": page}, playlist_list_params.PlaylistListParams), + ), + model=Playlist, + ) + + async def delete( + self, + playlist_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete playlist + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/streaming/playlists/{playlist_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + playlist_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Playlist: + """ + Returns a playlist details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/playlists/{playlist_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Playlist, + ) + + async def list_videos( + self, + playlist_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PlaylistListVideosResponse: + """ + Shows ordered array of playlist videos + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/playlists/{playlist_id}/videos", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PlaylistListVideosResponse, + ) + + +class PlaylistsResourceWithRawResponse: + def __init__(self, playlists: PlaylistsResource) -> None: + self._playlists = playlists + + self.create = to_raw_response_wrapper( + playlists.create, + ) + self.update = to_raw_response_wrapper( + playlists.update, + ) + self.list = to_raw_response_wrapper( + playlists.list, + ) + self.delete = to_raw_response_wrapper( + playlists.delete, + ) + self.get = to_raw_response_wrapper( + playlists.get, + ) + self.list_videos = to_raw_response_wrapper( + playlists.list_videos, + ) + + +class AsyncPlaylistsResourceWithRawResponse: + def __init__(self, playlists: AsyncPlaylistsResource) -> None: + self._playlists = playlists + + self.create = async_to_raw_response_wrapper( + playlists.create, + ) + self.update = async_to_raw_response_wrapper( + playlists.update, + ) + self.list = async_to_raw_response_wrapper( + playlists.list, + ) + self.delete = async_to_raw_response_wrapper( + playlists.delete, + ) + self.get = async_to_raw_response_wrapper( + playlists.get, + ) + self.list_videos = async_to_raw_response_wrapper( + playlists.list_videos, + ) + + +class PlaylistsResourceWithStreamingResponse: + def __init__(self, playlists: PlaylistsResource) -> None: + self._playlists = playlists + + self.create = to_streamed_response_wrapper( + playlists.create, + ) + self.update = to_streamed_response_wrapper( + playlists.update, + ) + self.list = to_streamed_response_wrapper( + playlists.list, + ) + self.delete = to_streamed_response_wrapper( + playlists.delete, + ) + self.get = to_streamed_response_wrapper( + playlists.get, + ) + self.list_videos = to_streamed_response_wrapper( + playlists.list_videos, + ) + + +class AsyncPlaylistsResourceWithStreamingResponse: + def __init__(self, playlists: AsyncPlaylistsResource) -> None: + self._playlists = playlists + + self.create = async_to_streamed_response_wrapper( + playlists.create, + ) + self.update = async_to_streamed_response_wrapper( + playlists.update, + ) + self.list = async_to_streamed_response_wrapper( + playlists.list, + ) + self.delete = async_to_streamed_response_wrapper( + playlists.delete, + ) + self.get = async_to_streamed_response_wrapper( + playlists.get, + ) + self.list_videos = async_to_streamed_response_wrapper( + playlists.list_videos, + ) diff --git a/src/gcore/resources/streaming/quality_sets.py b/src/gcore/resources/streaming/quality_sets.py new file mode 100644 index 00000000..4aff7843 --- /dev/null +++ b/src/gcore/resources/streaming/quality_sets.py @@ -0,0 +1,353 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.streaming import quality_set_set_default_params +from ...types.streaming.quality_sets import QualitySets + +__all__ = ["QualitySetsResource", "AsyncQualitySetsResource"] + + +class QualitySetsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> QualitySetsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return QualitySetsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> QualitySetsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return QualitySetsResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> QualitySets: + """ + Method returns a list of all custom quality sets. + + Transcoding is designed to minimize video file size while maintaining maximum + visual quality. This is done so that the video can be delivered and viewed on + any device, on any Internet connection, anywhere in the world. It's always a + compromise between video/audio quality and delivery+viewing quality (QoE). + + Our experts have selected the optimal parameters for transcoding, to ensure + maximum video/audio quality with the best compression. Default quality sets are + described in the + [documentation](/docs/streaming-platform/live-streams-and-videos-protocols-and-codecs/output-parameters-and-codecs#custom-quality-sets). + These values are the default for everyone. There is no need to configure + anything additional. + + Read more about qiality in our blog + [How we lowered the bitrate for live and VOD streaming by 32.5% without sacrificing quality](https://gcore.com/blog/how-we-lowered-the-bitrate-for-live-and-vod-streaming-by-32-5-without-sacrificing-quality). + + ![Quality ladder](https://demo-files.gvideo.io/apidocs/encoding_ladder.png) + + Only for those cases when, in addition to the main parameters, it is necessary + to use your own, then it is necessary to use custom quality sets. + + How to use: + + 1. By default custom quality set is empty – `{ "live":[],"vod":[] }` + 2. Request the use of custom quality sets from your manager or the Support Team. + 3. Please forward your requirements to us, since the parameters are set not by + you, but by our engineers. (We are working to ensure that later you can + create qualities by yourself.) + 4. Use the created quality sets through the these specified API methods. + + Here are some common parameters of quality settings: + + - Resolution: Determines the size of the video frame. I.e. 720p, 1080p, 4K, etc. + - Bitrate: Refers to the amount of data processed per unit of time. + - Codec: Codec used for transcoding can significantly affect quality. Popular + codecs include H.264 (AVC), H.265 (HEVC), and AV1. + - Frame Rate: Determines how many frames per second are displayed. Common frame + rates include 24fps, 30fps, and 60fps. + - Color Depth and Chroma Subsampling: These settings determine the accuracy of + color representation in the video. + - Audio Bitrate and Codec: Don't forget about the audio :) Bitrate and codec + used for audio can also affect the overall quality. Note: Custom quality set + is a paid feature. + """ + return self._get( + "/streaming/quality_sets", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=QualitySets, + ) + + def set_default( + self, + *, + live: quality_set_set_default_params.Live | Omit = omit, + vod: quality_set_set_default_params.Vod | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> QualitySets: + """ + Method to set default quality set for VOD and Live transcoding. + + For changing default quality set, specify the ID of the custom quality set from + the method GET /`quality_sets`. + + Default value can be reverted to the system defaults (cleared) by setting + `"id": null`. + + Live transcoding management: + + - You can specify quality set explicitly in POST /streams method, look at + attribute "quality_set_id". + - Otherwise these default values will be used by the system by default. + + VOD transcoding management: + + - You can specify quality set explicitly in POST /videos method, look at + attribute "quality_set_id". + - Otherwise these default values will be used by the system by default. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + "/streaming/quality_sets/default", + body=maybe_transform( + { + "live": live, + "vod": vod, + }, + quality_set_set_default_params.QualitySetSetDefaultParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=QualitySets, + ) + + +class AsyncQualitySetsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncQualitySetsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncQualitySetsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncQualitySetsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncQualitySetsResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> QualitySets: + """ + Method returns a list of all custom quality sets. + + Transcoding is designed to minimize video file size while maintaining maximum + visual quality. This is done so that the video can be delivered and viewed on + any device, on any Internet connection, anywhere in the world. It's always a + compromise between video/audio quality and delivery+viewing quality (QoE). + + Our experts have selected the optimal parameters for transcoding, to ensure + maximum video/audio quality with the best compression. Default quality sets are + described in the + [documentation](/docs/streaming-platform/live-streams-and-videos-protocols-and-codecs/output-parameters-and-codecs#custom-quality-sets). + These values are the default for everyone. There is no need to configure + anything additional. + + Read more about qiality in our blog + [How we lowered the bitrate for live and VOD streaming by 32.5% without sacrificing quality](https://gcore.com/blog/how-we-lowered-the-bitrate-for-live-and-vod-streaming-by-32-5-without-sacrificing-quality). + + ![Quality ladder](https://demo-files.gvideo.io/apidocs/encoding_ladder.png) + + Only for those cases when, in addition to the main parameters, it is necessary + to use your own, then it is necessary to use custom quality sets. + + How to use: + + 1. By default custom quality set is empty – `{ "live":[],"vod":[] }` + 2. Request the use of custom quality sets from your manager or the Support Team. + 3. Please forward your requirements to us, since the parameters are set not by + you, but by our engineers. (We are working to ensure that later you can + create qualities by yourself.) + 4. Use the created quality sets through the these specified API methods. + + Here are some common parameters of quality settings: + + - Resolution: Determines the size of the video frame. I.e. 720p, 1080p, 4K, etc. + - Bitrate: Refers to the amount of data processed per unit of time. + - Codec: Codec used for transcoding can significantly affect quality. Popular + codecs include H.264 (AVC), H.265 (HEVC), and AV1. + - Frame Rate: Determines how many frames per second are displayed. Common frame + rates include 24fps, 30fps, and 60fps. + - Color Depth and Chroma Subsampling: These settings determine the accuracy of + color representation in the video. + - Audio Bitrate and Codec: Don't forget about the audio :) Bitrate and codec + used for audio can also affect the overall quality. Note: Custom quality set + is a paid feature. + """ + return await self._get( + "/streaming/quality_sets", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=QualitySets, + ) + + async def set_default( + self, + *, + live: quality_set_set_default_params.Live | Omit = omit, + vod: quality_set_set_default_params.Vod | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> QualitySets: + """ + Method to set default quality set for VOD and Live transcoding. + + For changing default quality set, specify the ID of the custom quality set from + the method GET /`quality_sets`. + + Default value can be reverted to the system defaults (cleared) by setting + `"id": null`. + + Live transcoding management: + + - You can specify quality set explicitly in POST /streams method, look at + attribute "quality_set_id". + - Otherwise these default values will be used by the system by default. + + VOD transcoding management: + + - You can specify quality set explicitly in POST /videos method, look at + attribute "quality_set_id". + - Otherwise these default values will be used by the system by default. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + "/streaming/quality_sets/default", + body=await async_maybe_transform( + { + "live": live, + "vod": vod, + }, + quality_set_set_default_params.QualitySetSetDefaultParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=QualitySets, + ) + + +class QualitySetsResourceWithRawResponse: + def __init__(self, quality_sets: QualitySetsResource) -> None: + self._quality_sets = quality_sets + + self.list = to_raw_response_wrapper( + quality_sets.list, + ) + self.set_default = to_raw_response_wrapper( + quality_sets.set_default, + ) + + +class AsyncQualitySetsResourceWithRawResponse: + def __init__(self, quality_sets: AsyncQualitySetsResource) -> None: + self._quality_sets = quality_sets + + self.list = async_to_raw_response_wrapper( + quality_sets.list, + ) + self.set_default = async_to_raw_response_wrapper( + quality_sets.set_default, + ) + + +class QualitySetsResourceWithStreamingResponse: + def __init__(self, quality_sets: QualitySetsResource) -> None: + self._quality_sets = quality_sets + + self.list = to_streamed_response_wrapper( + quality_sets.list, + ) + self.set_default = to_streamed_response_wrapper( + quality_sets.set_default, + ) + + +class AsyncQualitySetsResourceWithStreamingResponse: + def __init__(self, quality_sets: AsyncQualitySetsResource) -> None: + self._quality_sets = quality_sets + + self.list = async_to_streamed_response_wrapper( + quality_sets.list, + ) + self.set_default = async_to_streamed_response_wrapper( + quality_sets.set_default, + ) diff --git a/src/gcore/resources/streaming/restreams.py b/src/gcore/resources/streaming/restreams.py new file mode 100644 index 00000000..91f24ab2 --- /dev/null +++ b/src/gcore/resources/streaming/restreams.py @@ -0,0 +1,484 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncPageStreaming, AsyncPageStreaming +from ..._base_client import AsyncPaginator, make_request_options +from ...types.streaming import restream_list_params, restream_create_params, restream_update_params +from ...types.streaming.restream import Restream + +__all__ = ["RestreamsResource", "AsyncRestreamsResource"] + + +class RestreamsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RestreamsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return RestreamsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RestreamsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return RestreamsResourceWithStreamingResponse(self) + + def create( + self, + *, + restream: restream_create_params.Restream | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Create restream + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + "/streaming/restreams", + body=maybe_transform({"restream": restream}, restream_create_params.RestreamCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def update( + self, + restream_id: int, + *, + restream: restream_update_params.Restream | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Restream: + """ + Updates restream settings + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/streaming/restreams/{restream_id}", + body=maybe_transform({"restream": restream}, restream_update_params.RestreamUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Restream, + ) + + def list( + self, + *, + page: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncPageStreaming[Restream]: + """Returns a list of created restreams + + Args: + page: Query parameter. + + Use it to list the paginated content + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/restreams", + page=SyncPageStreaming[Restream], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"page": page}, restream_list_params.RestreamListParams), + ), + model=Restream, + ) + + def delete( + self, + restream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete restream + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/streaming/restreams/{restream_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + restream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Restream: + """ + Returns restream details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/restreams/{restream_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Restream, + ) + + +class AsyncRestreamsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRestreamsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncRestreamsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRestreamsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncRestreamsResourceWithStreamingResponse(self) + + async def create( + self, + *, + restream: restream_create_params.Restream | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Create restream + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + "/streaming/restreams", + body=await async_maybe_transform({"restream": restream}, restream_create_params.RestreamCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def update( + self, + restream_id: int, + *, + restream: restream_update_params.Restream | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Restream: + """ + Updates restream settings + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/streaming/restreams/{restream_id}", + body=await async_maybe_transform({"restream": restream}, restream_update_params.RestreamUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Restream, + ) + + def list( + self, + *, + page: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Restream, AsyncPageStreaming[Restream]]: + """Returns a list of created restreams + + Args: + page: Query parameter. + + Use it to list the paginated content + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/restreams", + page=AsyncPageStreaming[Restream], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"page": page}, restream_list_params.RestreamListParams), + ), + model=Restream, + ) + + async def delete( + self, + restream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete restream + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/streaming/restreams/{restream_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + restream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Restream: + """ + Returns restream details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/restreams/{restream_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Restream, + ) + + +class RestreamsResourceWithRawResponse: + def __init__(self, restreams: RestreamsResource) -> None: + self._restreams = restreams + + self.create = to_raw_response_wrapper( + restreams.create, + ) + self.update = to_raw_response_wrapper( + restreams.update, + ) + self.list = to_raw_response_wrapper( + restreams.list, + ) + self.delete = to_raw_response_wrapper( + restreams.delete, + ) + self.get = to_raw_response_wrapper( + restreams.get, + ) + + +class AsyncRestreamsResourceWithRawResponse: + def __init__(self, restreams: AsyncRestreamsResource) -> None: + self._restreams = restreams + + self.create = async_to_raw_response_wrapper( + restreams.create, + ) + self.update = async_to_raw_response_wrapper( + restreams.update, + ) + self.list = async_to_raw_response_wrapper( + restreams.list, + ) + self.delete = async_to_raw_response_wrapper( + restreams.delete, + ) + self.get = async_to_raw_response_wrapper( + restreams.get, + ) + + +class RestreamsResourceWithStreamingResponse: + def __init__(self, restreams: RestreamsResource) -> None: + self._restreams = restreams + + self.create = to_streamed_response_wrapper( + restreams.create, + ) + self.update = to_streamed_response_wrapper( + restreams.update, + ) + self.list = to_streamed_response_wrapper( + restreams.list, + ) + self.delete = to_streamed_response_wrapper( + restreams.delete, + ) + self.get = to_streamed_response_wrapper( + restreams.get, + ) + + +class AsyncRestreamsResourceWithStreamingResponse: + def __init__(self, restreams: AsyncRestreamsResource) -> None: + self._restreams = restreams + + self.create = async_to_streamed_response_wrapper( + restreams.create, + ) + self.update = async_to_streamed_response_wrapper( + restreams.update, + ) + self.list = async_to_streamed_response_wrapper( + restreams.list, + ) + self.delete = async_to_streamed_response_wrapper( + restreams.delete, + ) + self.get = async_to_streamed_response_wrapper( + restreams.get, + ) diff --git a/src/gcore/resources/streaming/statistics.py b/src/gcore/resources/streaming/statistics.py new file mode 100644 index 00000000..234766df --- /dev/null +++ b/src/gcore/resources/streaming/statistics.py @@ -0,0 +1,3220 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.streaming import ( + statistic_get_views_params, + statistic_get_ffprobes_params, + statistic_get_stream_series_params, + statistic_get_views_heatmap_params, + statistic_get_popular_videos_params, + statistic_get_storage_series_params, + statistic_get_unique_viewers_params, + statistic_get_views_by_region_params, + statistic_get_views_by_country_params, + statistic_get_views_by_referer_params, + statistic_get_views_by_browsers_params, + statistic_get_views_by_hostname_params, + statistic_get_max_streams_series_params, + statistic_get_unique_viewers_cdn_params, + statistic_get_vod_storage_volume_params, + statistic_get_vod_watch_time_cdn_params, + statistic_get_live_unique_viewers_params, + statistic_get_live_watch_time_cdn_params, + statistic_get_vod_unique_viewers_cdn_params, + statistic_get_vod_transcoding_duration_params, + statistic_get_vod_watch_time_total_cdn_params, + statistic_get_live_watch_time_total_cdn_params, + statistic_get_views_by_operating_system_params, +) +from ...types.streaming.views import Views +from ...types.streaming.ffprobes import Ffprobes +from ...types.streaming.stream_series import StreamSeries +from ...types.streaming.views_heatmap import ViewsHeatmap +from ...types.streaming.popular_videos import PopularVideos +from ...types.streaming.storage_series import StorageSeries +from ...types.streaming.unique_viewers import UniqueViewers +from ...types.streaming.views_by_region import ViewsByRegion +from ...types.streaming.views_by_browser import ViewsByBrowser +from ...types.streaming.views_by_country import ViewsByCountry +from ...types.streaming.views_by_referer import ViewsByReferer +from ...types.streaming.max_stream_series import MaxStreamSeries +from ...types.streaming.views_by_hostname import ViewsByHostname +from ...types.streaming.unique_viewers_cdn import UniqueViewersCDN +from ...types.streaming.vod_statistics_series import VodStatisticsSeries +from ...types.streaming.views_by_operating_system import ViewsByOperatingSystem +from ...types.streaming.vod_total_stream_duration_series import VodTotalStreamDurationSeries +from ...types.streaming.statistic_get_live_unique_viewers_response import StatisticGetLiveUniqueViewersResponse +from ...types.streaming.statistic_get_vod_watch_time_total_cdn_response import StatisticGetVodWatchTimeTotalCDNResponse + +__all__ = ["StatisticsResource", "AsyncStatisticsResource"] + + +class StatisticsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> StatisticsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return StatisticsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> StatisticsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return StatisticsResourceWithStreamingResponse(self) + + def get_ffprobes( + self, + *, + date_from: str, + date_to: str, + stream_id: str, + interval: int | Omit = omit, + units: Literal["second", "minute", "hour", "day", "week", "month"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Ffprobes: + """ + Aggregates data for the specified video stream in the specified time interval. + "interval" and "units" params working together to point aggregation interval. + + You can use this method to watch when stream was alive in time, and when it was + off. + + Args: + date_from: Start of time frame. Format is ISO 8601. + + date_to: End of time frame. Datetime in ISO 8601 format. + + stream_id: Stream ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/ffprobe", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + "stream_id": stream_id, + "interval": interval, + "units": units, + }, + statistic_get_ffprobes_params.StatisticGetFfprobesParams, + ), + ), + cast_to=Ffprobes, + ) + + def get_live_unique_viewers( + self, + *, + from_: str, + to: str, + client_user_id: int | Omit = omit, + granularity: Literal["1m", "5m", "15m", "1h", "1d"] | Omit = omit, + stream_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StatisticGetLiveUniqueViewersResponse: + """ + Calculates time series of unique viewers of Live streams via CDN. + + The statistics are taken from the data of CDN and work regardless of which + player the views were made with. + + Works similar to the method `/statistics/cdn/uniqs`. But this allows you to + break down data with the specified granularity: minutes, hours, days. + + Based on this method, a graph of unique views in the Customer Portal is built. + + ![Unique viewers via CDN in Customer Portal](https://demo-files.gvideo.io/apidocs/cdn_unique_viewers.png) + + Args: + from_: Start of time frame. Format is date time in ISO 8601 + + to: End of time frame. Format is date time in ISO 8601 + + client_user_id: Filter by "client_user_id" + + granularity: Specifies the time interval for grouping data + + stream_id: Filter by "stream_id" + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/stream/viewers", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "to": to, + "client_user_id": client_user_id, + "granularity": granularity, + "stream_id": stream_id, + }, + statistic_get_live_unique_viewers_params.StatisticGetLiveUniqueViewersParams, + ), + ), + cast_to=StatisticGetLiveUniqueViewersResponse, + ) + + def get_live_watch_time_cdn( + self, + *, + from_: str, + client_user_id: int | Omit = omit, + granularity: Literal["1m", "5m", "15m", "1h", "1d", "1mo"] | Omit = omit, + stream_id: int | Omit = omit, + to: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StreamSeries: + """Calculates a time series of live streams watching duration in minutes. + + Views of + only those streams that meet the specified filters are summed up. + + The statistics are taken from the data of CDN and work regardless of which + player the views were made with. + + Please note that the result for each time interval is in minutes, it is rounded + to the nearest upper integer. You cannot use the sum of all intervals as the + total watch time value; instead, use the /total method. + + Args: + from_: Start of the time period for counting minutes of watching. Format is date time + in ISO 8601. + + client_user_id: Filter by field "client_user_id" + + granularity: Data is grouped by the specified time interval + + stream_id: Filter by `stream_id` + + to: End of time frame. Datetime in ISO 8601 format. If omitted, then the current + time is taken + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/stream/watching_duration", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "client_user_id": client_user_id, + "granularity": granularity, + "stream_id": stream_id, + "to": to, + }, + statistic_get_live_watch_time_cdn_params.StatisticGetLiveWatchTimeCDNParams, + ), + ), + cast_to=StreamSeries, + ) + + def get_live_watch_time_total_cdn( + self, + *, + client_user_id: int | Omit = omit, + from_: str | Omit = omit, + stream_id: int | Omit = omit, + to: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VodTotalStreamDurationSeries: + """Calculates the total duration of live streams watching in minutes. + + Views of only + those streams that meet the specified filters are summed up. + + The statistics are taken from the data of CDN and work regardless of which + player the views were made with. + + Args: + client_user_id: Filter by field "client_user_id" + + from_: Start of the time period for counting minutes of watching. Format is date time + in ISO 8601. If omitted, the earliest start time for viewing is taken + + stream_id: Filter by `stream_id` + + to: End of time frame. Datetime in ISO 8601 format. If missed, then the current time + is taken + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/stream/watching_duration/total", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "client_user_id": client_user_id, + "from_": from_, + "stream_id": stream_id, + "to": to, + }, + statistic_get_live_watch_time_total_cdn_params.StatisticGetLiveWatchTimeTotalCDNParams, + ), + ), + cast_to=VodTotalStreamDurationSeries, + ) + + def get_max_streams_series( + self, + *, + from_: str, + to: str, + granularity: Literal["1m", "5m", "15m", "1h", "1d"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MaxStreamSeries: + """Calculates time series of the amount of simultaneous streams. + + The data is + updated near realtime. + + Args: + from_: Start of time frame. Datetime in ISO 8601 format. + + to: End of time frame. Datetime in ISO 8601 format. + + granularity: specifies the time interval for grouping data + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/max_stream", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "to": to, + "granularity": granularity, + }, + statistic_get_max_streams_series_params.StatisticGetMaxStreamsSeriesParams, + ), + ), + cast_to=MaxStreamSeries, + ) + + def get_popular_videos( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PopularVideos: + """ + Aggregates the number of views for all client videos, grouping them by id and + sort from most popular to less in the built-in player. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/popular", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_popular_videos_params.StatisticGetPopularVideosParams, + ), + ), + cast_to=PopularVideos, + ) + + def get_storage_series( + self, + *, + from_: str, + to: str, + granularity: Literal["1m", "5m", "15m", "1h", "1d"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StorageSeries: + """ + Calculates time series of the size of disk space in bytes for all processed and + undeleted client videos. The data is updated every 8 hours, it does not make + sense to set the granulation less than 1 day. + + Args: + from_: Start of time frame. Datetime in ISO 8601 format. + + to: End of time frame. Datetime in ISO 8601 format. + + granularity: specifies the time interval for grouping data + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/storage", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "to": to, + "granularity": granularity, + }, + statistic_get_storage_series_params.StatisticGetStorageSeriesParams, + ), + ), + cast_to=StorageSeries, + ) + + def get_stream_series( + self, + *, + from_: str, + to: str, + granularity: Literal["1m", "5m", "15m", "1h", "1d"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StreamSeries: + """Calculates time series of the transcoding minutes of all streams. + + The data is + updated near realtime. + + Args: + from_: Start of time frame. Datetime in ISO 8601 format. + + to: End of time frame. Datetime in ISO 8601 format. + + granularity: specifies the time interval for grouping data + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/stream", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "to": to, + "granularity": granularity, + }, + statistic_get_stream_series_params.StatisticGetStreamSeriesParams, + ), + ), + cast_to=StreamSeries, + ) + + def get_unique_viewers( + self, + *, + date_from: str, + date_to: str, + id: str | Omit = omit, + country: str | Omit = omit, + event: Literal["init", "start", "watch"] | Omit = omit, + group: List[Literal["date", "host", "os", "browser", "platform", "ip", "country", "event", "id"]] | Omit = omit, + host: str | Omit = omit, + type: Literal["live", "vod", "playlist"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UniqueViewers: + """ + Get the number of unique viewers in the built-in player. + + Counts the number of unique IPs. + + Allows flexible grouping and filtering. The fields in the response depend on the + selected grouping. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + id: filter by entity's id + + country: filter by country + + event: filter by event's name + + group: group=1,2,4 OR group=1&group=2&group=3 + + host: filter by host + + type: filter by entity's type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/uniqs", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + "id": id, + "country": country, + "event": event, + "group": group, + "host": host, + "type": type, + }, + statistic_get_unique_viewers_params.StatisticGetUniqueViewersParams, + ), + ), + cast_to=UniqueViewers, + ) + + def get_unique_viewers_cdn( + self, + *, + date_from: str, + date_to: str, + id: str | Omit = omit, + type: Literal["live", "vod", "playlist"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UniqueViewersCDN: + """Сounts the number of unique viewers of a video entity over CDN. + + It doesn't + matter what player you used. + + All unique viewers for the specified period of time are counted. + + **How does it work?** + + Calculating the number of unique viewers for a Live stream or VOD over CDN + involves aggregating and analyzing various metrics to ensure each individual + viewer is counted only once, regardless of how many times they connect or + disconnect during the stream. + + This method provides statistics for any video viewing by unique users, + regardless of viewing method and a player you used. Thus, this is the most + important difference from viewing through the built-in player: + + - In method /statistics/uniqs viewers of the built-in player are tracked only. + - But this method tracks all viewers from everywhere. + + This method is a combination of two other Live and VOD detailed methods. If you + need detailed information, then see the methods: `/statistics/stream/viewers` + and `/statistics/vod/viewers`. + + **Data Processing and Deduplication** + + We us IP Address & User-Agent combination. Each unique combination of IP address + and User-Agent string might be considered a unique viewer. + + This approach allows to accurately estimate the number of unique viewers. + However, this is not foolproof due to NAT (Network Address Translation) and + shared networks. Thus if your users fall under such restrictions, then the + number of unique viewers may be higher than calculated. + + **Why is there no "Unique Views" method?** + + Based on CDN data, we can calculate the number of unique viewers only. Thus only + your player will be able to count the number of unique views (clicks on the Play + button) within the player session (i.e. how many times 1 unique viewer clicked + the Play button within a unique player's session). + + Args: + date_from: Start of time frame. Format is date time in ISO 8601. + + date_to: End of time frame. Format is date time in ISO 8601. + + id: Filter by entity's id. Put ID of a Live stream, VOD or a playlist to be + calculated. + + If the value is omitted, then the calculation is done for all videos/streams of + the specified type. + + When using this "id" parameter, be sure to specify the "type" parameter too. If + you do not specify a type, the "id" will be ignored. + + type: Filter by entity's type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/cdn/uniqs", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + "id": id, + "type": type, + }, + statistic_get_unique_viewers_cdn_params.StatisticGetUniqueViewersCDNParams, + ), + ), + cast_to=UniqueViewersCDN, + ) + + def get_views( + self, + *, + date_from: str, + date_to: str, + id: str | Omit = omit, + country: str | Omit = omit, + event: Literal["init", "start", "watch"] | Omit = omit, + group: List[Literal["host", "os", "browser", "platform", "ip", "country", "event", "id"]] | Omit = omit, + host: str | Omit = omit, + type: Literal["live", "vod", "playlist"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Views: + """ + Get the number of views in the built-in player. + + Allows flexible grouping and filtering. The fields in the response depend on the + selected grouping. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + id: filter by entity's id + + country: filter by country + + event: filter by event's name + + group: group=1,2,4 OR group=1&group=2&group=3 + + host: filter by host + + type: filter by entity's type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/views", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + "id": id, + "country": country, + "event": event, + "group": group, + "host": host, + "type": type, + }, + statistic_get_views_params.StatisticGetViewsParams, + ), + ), + cast_to=Views, + ) + + def get_views_by_browsers( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsByBrowser: + """ + Aggregates the number of views for all client videos, grouping them by browsers + in the built-in player. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/browsers", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_views_by_browsers_params.StatisticGetViewsByBrowsersParams, + ), + ), + cast_to=ViewsByBrowser, + ) + + def get_views_by_country( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsByCountry: + """ + Aggregates the number of views grouping them by country in the built-in player. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/countries", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_views_by_country_params.StatisticGetViewsByCountryParams, + ), + ), + cast_to=ViewsByCountry, + ) + + def get_views_by_hostname( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsByHostname: + """ + Aggregates the number of views, grouping them by "host" domain name the built-in + player was embeded to. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/hosts", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_views_by_hostname_params.StatisticGetViewsByHostnameParams, + ), + ), + cast_to=ViewsByHostname, + ) + + def get_views_by_operating_system( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsByOperatingSystem: + """ + Aggregates the number of views for all client videos, grouping them by device + OSs in the built-in player. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/systems", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_views_by_operating_system_params.StatisticGetViewsByOperatingSystemParams, + ), + ), + cast_to=ViewsByOperatingSystem, + ) + + def get_views_by_referer( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsByReferer: + """ + Aggregates the number of views, grouping them by "referer" URL of pages the + built-in player was embeded to. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/embeds", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_views_by_referer_params.StatisticGetViewsByRefererParams, + ), + ), + cast_to=ViewsByReferer, + ) + + def get_views_by_region( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsByRegion: + """ + Aggregates the number of views grouping them by regions of countries in the + built-in player. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/regions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_views_by_region_params.StatisticGetViewsByRegionParams, + ), + ), + cast_to=ViewsByRegion, + ) + + def get_views_heatmap( + self, + *, + date_from: str, + date_to: str, + stream_id: str, + type: Literal["live", "vod", "playlist"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsHeatmap: + """ + Shows information about what part of the video your viewers watched in the + built-in player. + + This way you can find out how many viewers started watching the video, and where + they stopped watching instead of watching the entire video to the end. + + Has different format of response depends on query param "type". + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + stream_id: video streaming ID + + type: entity's type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/heatmap", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + "stream_id": stream_id, + "type": type, + }, + statistic_get_views_heatmap_params.StatisticGetViewsHeatmapParams, + ), + ), + cast_to=ViewsHeatmap, + ) + + def get_vod_storage_volume( + self, + *, + from_: str, + to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VodStatisticsSeries: + """ + Calculates time series of the duration in minutes for all processed and + undeleted client videos. + + The data is updated every 8 hours, it does not make sense to set the granulation + less than 1 day. + + Args: + from_: Start of time frame. Datetime in ISO 8601 format. + + to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/vod/storage_duration", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "to": to, + }, + statistic_get_vod_storage_volume_params.StatisticGetVodStorageVolumeParams, + ), + ), + cast_to=VodStatisticsSeries, + ) + + def get_vod_transcoding_duration( + self, + *, + from_: str, + to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VodStatisticsSeries: + """ + Calculates time series of the transcoding time in minutes for all processed + client videos. + + The data is updated every 8 hours, it does not make sense to set the granulation + less than 1 day. + + Args: + from_: Start of time frame. Datetime in ISO 8601 format. + + to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/vod/transcoding_duration", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "to": to, + }, + statistic_get_vod_transcoding_duration_params.StatisticGetVodTranscodingDurationParams, + ), + ), + cast_to=VodStatisticsSeries, + ) + + def get_vod_unique_viewers_cdn( + self, + *, + from_: str, + to: str, + client_user_id: int | Omit = omit, + granularity: Literal["1m", "5m", "15m", "1h", "1d"] | Omit = omit, + slug: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VodStatisticsSeries: + """ + Calculates time series of unique viewers of VOD via CDN. + + The statistics are taken from the data of CDN and work regardless of which + player the views were made with. + + Works similar to the method `/statistics/cdn/uniqs`. But this allows you to + break down data with the specified granularity: minutes, hours, days. + + Based on this method, a graph of unique views in the Customer Portal is built. + + ![Unique viewers via CDN in Customer Portal](https://demo-files.gvideo.io/apidocs/cdn_unique_viewers.png) + + Args: + from_: Start of time frame. Format is date time in ISO 8601 + + to: End of time frame. Format is date time in ISO 8601 + + client_user_id: Filter by user "id" + + granularity: Specifies the time interval for grouping data + + slug: Filter by video "slug" + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/vod/viewers", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "to": to, + "client_user_id": client_user_id, + "granularity": granularity, + "slug": slug, + }, + statistic_get_vod_unique_viewers_cdn_params.StatisticGetVodUniqueViewersCDNParams, + ), + ), + cast_to=VodStatisticsSeries, + ) + + def get_vod_watch_time_cdn( + self, + *, + from_: str, + client_user_id: int | Omit = omit, + granularity: Literal["1m", "5m", "15m", "1h", "1d", "1mo"] | Omit = omit, + slug: str | Omit = omit, + to: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VodStatisticsSeries: + """Calculates a time series of video watching duration in minutes. + + Views of only + those videos that meet the specified filters are summed up. + + The statistics are taken from the data of CDN and work regardless of which + player the views were made with. + + Please note that the result for each time interval is in minutes, it is rounded + to the nearest upper integer. You cannot use the sum of all intervals as the + total watch time value; instead, use the /total method. + + Args: + from_: Start of the time period for counting minutes of watching. Format is date time + in ISO 8601. + + client_user_id: Filter by field "client_user_id" + + granularity: Data is grouped by the specified time interval + + slug: Filter by video's slug + + to: End of time frame. Datetime in ISO 8601 format. If omitted, then the current + time is taken. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/vod/watching_duration", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "client_user_id": client_user_id, + "granularity": granularity, + "slug": slug, + "to": to, + }, + statistic_get_vod_watch_time_cdn_params.StatisticGetVodWatchTimeCDNParams, + ), + ), + cast_to=VodStatisticsSeries, + ) + + def get_vod_watch_time_total_cdn( + self, + *, + client_user_id: int | Omit = omit, + from_: str | Omit = omit, + slug: str | Omit = omit, + to: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StatisticGetVodWatchTimeTotalCDNResponse: + """Calculates the total duration of video watching in minutes. + + Views of only those + videos that meet the specified filters are summed up. + + The statistics are taken from the data of CDN and work regardless of which + player the views were made with. + + Args: + client_user_id: Filter by field "client_user_id" + + from_: Start of the time period for counting minutes of watching. Format is date time + in ISO 8601. If omitted, the earliest start time for viewing is taken + + slug: Filter by video's slug + + to: End of time frame. Datetime in ISO 8601 format. If omitted, then the current + time is taken + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/streaming/statistics/vod/watching_duration/total", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "client_user_id": client_user_id, + "from_": from_, + "slug": slug, + "to": to, + }, + statistic_get_vod_watch_time_total_cdn_params.StatisticGetVodWatchTimeTotalCDNParams, + ), + ), + cast_to=StatisticGetVodWatchTimeTotalCDNResponse, + ) + + +class AsyncStatisticsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncStatisticsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncStatisticsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncStatisticsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncStatisticsResourceWithStreamingResponse(self) + + async def get_ffprobes( + self, + *, + date_from: str, + date_to: str, + stream_id: str, + interval: int | Omit = omit, + units: Literal["second", "minute", "hour", "day", "week", "month"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Ffprobes: + """ + Aggregates data for the specified video stream in the specified time interval. + "interval" and "units" params working together to point aggregation interval. + + You can use this method to watch when stream was alive in time, and when it was + off. + + Args: + date_from: Start of time frame. Format is ISO 8601. + + date_to: End of time frame. Datetime in ISO 8601 format. + + stream_id: Stream ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/ffprobe", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + "stream_id": stream_id, + "interval": interval, + "units": units, + }, + statistic_get_ffprobes_params.StatisticGetFfprobesParams, + ), + ), + cast_to=Ffprobes, + ) + + async def get_live_unique_viewers( + self, + *, + from_: str, + to: str, + client_user_id: int | Omit = omit, + granularity: Literal["1m", "5m", "15m", "1h", "1d"] | Omit = omit, + stream_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StatisticGetLiveUniqueViewersResponse: + """ + Calculates time series of unique viewers of Live streams via CDN. + + The statistics are taken from the data of CDN and work regardless of which + player the views were made with. + + Works similar to the method `/statistics/cdn/uniqs`. But this allows you to + break down data with the specified granularity: minutes, hours, days. + + Based on this method, a graph of unique views in the Customer Portal is built. + + ![Unique viewers via CDN in Customer Portal](https://demo-files.gvideo.io/apidocs/cdn_unique_viewers.png) + + Args: + from_: Start of time frame. Format is date time in ISO 8601 + + to: End of time frame. Format is date time in ISO 8601 + + client_user_id: Filter by "client_user_id" + + granularity: Specifies the time interval for grouping data + + stream_id: Filter by "stream_id" + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/stream/viewers", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "to": to, + "client_user_id": client_user_id, + "granularity": granularity, + "stream_id": stream_id, + }, + statistic_get_live_unique_viewers_params.StatisticGetLiveUniqueViewersParams, + ), + ), + cast_to=StatisticGetLiveUniqueViewersResponse, + ) + + async def get_live_watch_time_cdn( + self, + *, + from_: str, + client_user_id: int | Omit = omit, + granularity: Literal["1m", "5m", "15m", "1h", "1d", "1mo"] | Omit = omit, + stream_id: int | Omit = omit, + to: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StreamSeries: + """Calculates a time series of live streams watching duration in minutes. + + Views of + only those streams that meet the specified filters are summed up. + + The statistics are taken from the data of CDN and work regardless of which + player the views were made with. + + Please note that the result for each time interval is in minutes, it is rounded + to the nearest upper integer. You cannot use the sum of all intervals as the + total watch time value; instead, use the /total method. + + Args: + from_: Start of the time period for counting minutes of watching. Format is date time + in ISO 8601. + + client_user_id: Filter by field "client_user_id" + + granularity: Data is grouped by the specified time interval + + stream_id: Filter by `stream_id` + + to: End of time frame. Datetime in ISO 8601 format. If omitted, then the current + time is taken + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/stream/watching_duration", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "client_user_id": client_user_id, + "granularity": granularity, + "stream_id": stream_id, + "to": to, + }, + statistic_get_live_watch_time_cdn_params.StatisticGetLiveWatchTimeCDNParams, + ), + ), + cast_to=StreamSeries, + ) + + async def get_live_watch_time_total_cdn( + self, + *, + client_user_id: int | Omit = omit, + from_: str | Omit = omit, + stream_id: int | Omit = omit, + to: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VodTotalStreamDurationSeries: + """Calculates the total duration of live streams watching in minutes. + + Views of only + those streams that meet the specified filters are summed up. + + The statistics are taken from the data of CDN and work regardless of which + player the views were made with. + + Args: + client_user_id: Filter by field "client_user_id" + + from_: Start of the time period for counting minutes of watching. Format is date time + in ISO 8601. If omitted, the earliest start time for viewing is taken + + stream_id: Filter by `stream_id` + + to: End of time frame. Datetime in ISO 8601 format. If missed, then the current time + is taken + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/stream/watching_duration/total", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "client_user_id": client_user_id, + "from_": from_, + "stream_id": stream_id, + "to": to, + }, + statistic_get_live_watch_time_total_cdn_params.StatisticGetLiveWatchTimeTotalCDNParams, + ), + ), + cast_to=VodTotalStreamDurationSeries, + ) + + async def get_max_streams_series( + self, + *, + from_: str, + to: str, + granularity: Literal["1m", "5m", "15m", "1h", "1d"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MaxStreamSeries: + """Calculates time series of the amount of simultaneous streams. + + The data is + updated near realtime. + + Args: + from_: Start of time frame. Datetime in ISO 8601 format. + + to: End of time frame. Datetime in ISO 8601 format. + + granularity: specifies the time interval for grouping data + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/max_stream", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "to": to, + "granularity": granularity, + }, + statistic_get_max_streams_series_params.StatisticGetMaxStreamsSeriesParams, + ), + ), + cast_to=MaxStreamSeries, + ) + + async def get_popular_videos( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> PopularVideos: + """ + Aggregates the number of views for all client videos, grouping them by id and + sort from most popular to less in the built-in player. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/popular", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_popular_videos_params.StatisticGetPopularVideosParams, + ), + ), + cast_to=PopularVideos, + ) + + async def get_storage_series( + self, + *, + from_: str, + to: str, + granularity: Literal["1m", "5m", "15m", "1h", "1d"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StorageSeries: + """ + Calculates time series of the size of disk space in bytes for all processed and + undeleted client videos. The data is updated every 8 hours, it does not make + sense to set the granulation less than 1 day. + + Args: + from_: Start of time frame. Datetime in ISO 8601 format. + + to: End of time frame. Datetime in ISO 8601 format. + + granularity: specifies the time interval for grouping data + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/storage", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "to": to, + "granularity": granularity, + }, + statistic_get_storage_series_params.StatisticGetStorageSeriesParams, + ), + ), + cast_to=StorageSeries, + ) + + async def get_stream_series( + self, + *, + from_: str, + to: str, + granularity: Literal["1m", "5m", "15m", "1h", "1d"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StreamSeries: + """Calculates time series of the transcoding minutes of all streams. + + The data is + updated near realtime. + + Args: + from_: Start of time frame. Datetime in ISO 8601 format. + + to: End of time frame. Datetime in ISO 8601 format. + + granularity: specifies the time interval for grouping data + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/stream", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "to": to, + "granularity": granularity, + }, + statistic_get_stream_series_params.StatisticGetStreamSeriesParams, + ), + ), + cast_to=StreamSeries, + ) + + async def get_unique_viewers( + self, + *, + date_from: str, + date_to: str, + id: str | Omit = omit, + country: str | Omit = omit, + event: Literal["init", "start", "watch"] | Omit = omit, + group: List[Literal["date", "host", "os", "browser", "platform", "ip", "country", "event", "id"]] | Omit = omit, + host: str | Omit = omit, + type: Literal["live", "vod", "playlist"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UniqueViewers: + """ + Get the number of unique viewers in the built-in player. + + Counts the number of unique IPs. + + Allows flexible grouping and filtering. The fields in the response depend on the + selected grouping. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + id: filter by entity's id + + country: filter by country + + event: filter by event's name + + group: group=1,2,4 OR group=1&group=2&group=3 + + host: filter by host + + type: filter by entity's type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/uniqs", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + "id": id, + "country": country, + "event": event, + "group": group, + "host": host, + "type": type, + }, + statistic_get_unique_viewers_params.StatisticGetUniqueViewersParams, + ), + ), + cast_to=UniqueViewers, + ) + + async def get_unique_viewers_cdn( + self, + *, + date_from: str, + date_to: str, + id: str | Omit = omit, + type: Literal["live", "vod", "playlist"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UniqueViewersCDN: + """Сounts the number of unique viewers of a video entity over CDN. + + It doesn't + matter what player you used. + + All unique viewers for the specified period of time are counted. + + **How does it work?** + + Calculating the number of unique viewers for a Live stream or VOD over CDN + involves aggregating and analyzing various metrics to ensure each individual + viewer is counted only once, regardless of how many times they connect or + disconnect during the stream. + + This method provides statistics for any video viewing by unique users, + regardless of viewing method and a player you used. Thus, this is the most + important difference from viewing through the built-in player: + + - In method /statistics/uniqs viewers of the built-in player are tracked only. + - But this method tracks all viewers from everywhere. + + This method is a combination of two other Live and VOD detailed methods. If you + need detailed information, then see the methods: `/statistics/stream/viewers` + and `/statistics/vod/viewers`. + + **Data Processing and Deduplication** + + We us IP Address & User-Agent combination. Each unique combination of IP address + and User-Agent string might be considered a unique viewer. + + This approach allows to accurately estimate the number of unique viewers. + However, this is not foolproof due to NAT (Network Address Translation) and + shared networks. Thus if your users fall under such restrictions, then the + number of unique viewers may be higher than calculated. + + **Why is there no "Unique Views" method?** + + Based on CDN data, we can calculate the number of unique viewers only. Thus only + your player will be able to count the number of unique views (clicks on the Play + button) within the player session (i.e. how many times 1 unique viewer clicked + the Play button within a unique player's session). + + Args: + date_from: Start of time frame. Format is date time in ISO 8601. + + date_to: End of time frame. Format is date time in ISO 8601. + + id: Filter by entity's id. Put ID of a Live stream, VOD or a playlist to be + calculated. + + If the value is omitted, then the calculation is done for all videos/streams of + the specified type. + + When using this "id" parameter, be sure to specify the "type" parameter too. If + you do not specify a type, the "id" will be ignored. + + type: Filter by entity's type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/cdn/uniqs", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + "id": id, + "type": type, + }, + statistic_get_unique_viewers_cdn_params.StatisticGetUniqueViewersCDNParams, + ), + ), + cast_to=UniqueViewersCDN, + ) + + async def get_views( + self, + *, + date_from: str, + date_to: str, + id: str | Omit = omit, + country: str | Omit = omit, + event: Literal["init", "start", "watch"] | Omit = omit, + group: List[Literal["host", "os", "browser", "platform", "ip", "country", "event", "id"]] | Omit = omit, + host: str | Omit = omit, + type: Literal["live", "vod", "playlist"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Views: + """ + Get the number of views in the built-in player. + + Allows flexible grouping and filtering. The fields in the response depend on the + selected grouping. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + id: filter by entity's id + + country: filter by country + + event: filter by event's name + + group: group=1,2,4 OR group=1&group=2&group=3 + + host: filter by host + + type: filter by entity's type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/views", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + "id": id, + "country": country, + "event": event, + "group": group, + "host": host, + "type": type, + }, + statistic_get_views_params.StatisticGetViewsParams, + ), + ), + cast_to=Views, + ) + + async def get_views_by_browsers( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsByBrowser: + """ + Aggregates the number of views for all client videos, grouping them by browsers + in the built-in player. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/browsers", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_views_by_browsers_params.StatisticGetViewsByBrowsersParams, + ), + ), + cast_to=ViewsByBrowser, + ) + + async def get_views_by_country( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsByCountry: + """ + Aggregates the number of views grouping them by country in the built-in player. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/countries", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_views_by_country_params.StatisticGetViewsByCountryParams, + ), + ), + cast_to=ViewsByCountry, + ) + + async def get_views_by_hostname( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsByHostname: + """ + Aggregates the number of views, grouping them by "host" domain name the built-in + player was embeded to. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/hosts", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_views_by_hostname_params.StatisticGetViewsByHostnameParams, + ), + ), + cast_to=ViewsByHostname, + ) + + async def get_views_by_operating_system( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsByOperatingSystem: + """ + Aggregates the number of views for all client videos, grouping them by device + OSs in the built-in player. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/systems", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_views_by_operating_system_params.StatisticGetViewsByOperatingSystemParams, + ), + ), + cast_to=ViewsByOperatingSystem, + ) + + async def get_views_by_referer( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsByReferer: + """ + Aggregates the number of views, grouping them by "referer" URL of pages the + built-in player was embeded to. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/embeds", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_views_by_referer_params.StatisticGetViewsByRefererParams, + ), + ), + cast_to=ViewsByReferer, + ) + + async def get_views_by_region( + self, + *, + date_from: str, + date_to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsByRegion: + """ + Aggregates the number of views grouping them by regions of countries in the + built-in player. + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/regions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + }, + statistic_get_views_by_region_params.StatisticGetViewsByRegionParams, + ), + ), + cast_to=ViewsByRegion, + ) + + async def get_views_heatmap( + self, + *, + date_from: str, + date_to: str, + stream_id: str, + type: Literal["live", "vod", "playlist"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ViewsHeatmap: + """ + Shows information about what part of the video your viewers watched in the + built-in player. + + This way you can find out how many viewers started watching the video, and where + they stopped watching instead of watching the entire video to the end. + + Has different format of response depends on query param "type". + + Note. This method operates only on data collected by the built-in HTML player. + It will not show statistics if you are using another player or viewing in native + OS players through direct .m3u8/.mpd/.mp4 links. For such cases, use + calculations through CDN (look at method /statistics/cdn/uniqs) or statistics of + the players you have chosen. + + Args: + date_from: Start of time frame. Datetime in ISO 8601 format. + + date_to: End of time frame. Datetime in ISO 8601 format. + + stream_id: video streaming ID + + type: entity's type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/heatmap", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "date_from": date_from, + "date_to": date_to, + "stream_id": stream_id, + "type": type, + }, + statistic_get_views_heatmap_params.StatisticGetViewsHeatmapParams, + ), + ), + cast_to=ViewsHeatmap, + ) + + async def get_vod_storage_volume( + self, + *, + from_: str, + to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VodStatisticsSeries: + """ + Calculates time series of the duration in minutes for all processed and + undeleted client videos. + + The data is updated every 8 hours, it does not make sense to set the granulation + less than 1 day. + + Args: + from_: Start of time frame. Datetime in ISO 8601 format. + + to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/vod/storage_duration", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "to": to, + }, + statistic_get_vod_storage_volume_params.StatisticGetVodStorageVolumeParams, + ), + ), + cast_to=VodStatisticsSeries, + ) + + async def get_vod_transcoding_duration( + self, + *, + from_: str, + to: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VodStatisticsSeries: + """ + Calculates time series of the transcoding time in minutes for all processed + client videos. + + The data is updated every 8 hours, it does not make sense to set the granulation + less than 1 day. + + Args: + from_: Start of time frame. Datetime in ISO 8601 format. + + to: End of time frame. Datetime in ISO 8601 format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/vod/transcoding_duration", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "to": to, + }, + statistic_get_vod_transcoding_duration_params.StatisticGetVodTranscodingDurationParams, + ), + ), + cast_to=VodStatisticsSeries, + ) + + async def get_vod_unique_viewers_cdn( + self, + *, + from_: str, + to: str, + client_user_id: int | Omit = omit, + granularity: Literal["1m", "5m", "15m", "1h", "1d"] | Omit = omit, + slug: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VodStatisticsSeries: + """ + Calculates time series of unique viewers of VOD via CDN. + + The statistics are taken from the data of CDN and work regardless of which + player the views were made with. + + Works similar to the method `/statistics/cdn/uniqs`. But this allows you to + break down data with the specified granularity: minutes, hours, days. + + Based on this method, a graph of unique views in the Customer Portal is built. + + ![Unique viewers via CDN in Customer Portal](https://demo-files.gvideo.io/apidocs/cdn_unique_viewers.png) + + Args: + from_: Start of time frame. Format is date time in ISO 8601 + + to: End of time frame. Format is date time in ISO 8601 + + client_user_id: Filter by user "id" + + granularity: Specifies the time interval for grouping data + + slug: Filter by video "slug" + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/vod/viewers", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "to": to, + "client_user_id": client_user_id, + "granularity": granularity, + "slug": slug, + }, + statistic_get_vod_unique_viewers_cdn_params.StatisticGetVodUniqueViewersCDNParams, + ), + ), + cast_to=VodStatisticsSeries, + ) + + async def get_vod_watch_time_cdn( + self, + *, + from_: str, + client_user_id: int | Omit = omit, + granularity: Literal["1m", "5m", "15m", "1h", "1d", "1mo"] | Omit = omit, + slug: str | Omit = omit, + to: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VodStatisticsSeries: + """Calculates a time series of video watching duration in minutes. + + Views of only + those videos that meet the specified filters are summed up. + + The statistics are taken from the data of CDN and work regardless of which + player the views were made with. + + Please note that the result for each time interval is in minutes, it is rounded + to the nearest upper integer. You cannot use the sum of all intervals as the + total watch time value; instead, use the /total method. + + Args: + from_: Start of the time period for counting minutes of watching. Format is date time + in ISO 8601. + + client_user_id: Filter by field "client_user_id" + + granularity: Data is grouped by the specified time interval + + slug: Filter by video's slug + + to: End of time frame. Datetime in ISO 8601 format. If omitted, then the current + time is taken. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/vod/watching_duration", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "client_user_id": client_user_id, + "granularity": granularity, + "slug": slug, + "to": to, + }, + statistic_get_vod_watch_time_cdn_params.StatisticGetVodWatchTimeCDNParams, + ), + ), + cast_to=VodStatisticsSeries, + ) + + async def get_vod_watch_time_total_cdn( + self, + *, + client_user_id: int | Omit = omit, + from_: str | Omit = omit, + slug: str | Omit = omit, + to: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StatisticGetVodWatchTimeTotalCDNResponse: + """Calculates the total duration of video watching in minutes. + + Views of only those + videos that meet the specified filters are summed up. + + The statistics are taken from the data of CDN and work regardless of which + player the views were made with. + + Args: + client_user_id: Filter by field "client_user_id" + + from_: Start of the time period for counting minutes of watching. Format is date time + in ISO 8601. If omitted, the earliest start time for viewing is taken + + slug: Filter by video's slug + + to: End of time frame. Datetime in ISO 8601 format. If omitted, then the current + time is taken + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/streaming/statistics/vod/watching_duration/total", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "client_user_id": client_user_id, + "from_": from_, + "slug": slug, + "to": to, + }, + statistic_get_vod_watch_time_total_cdn_params.StatisticGetVodWatchTimeTotalCDNParams, + ), + ), + cast_to=StatisticGetVodWatchTimeTotalCDNResponse, + ) + + +class StatisticsResourceWithRawResponse: + def __init__(self, statistics: StatisticsResource) -> None: + self._statistics = statistics + + self.get_ffprobes = to_raw_response_wrapper( + statistics.get_ffprobes, + ) + self.get_live_unique_viewers = to_raw_response_wrapper( + statistics.get_live_unique_viewers, + ) + self.get_live_watch_time_cdn = to_raw_response_wrapper( + statistics.get_live_watch_time_cdn, + ) + self.get_live_watch_time_total_cdn = to_raw_response_wrapper( + statistics.get_live_watch_time_total_cdn, + ) + self.get_max_streams_series = to_raw_response_wrapper( + statistics.get_max_streams_series, + ) + self.get_popular_videos = to_raw_response_wrapper( + statistics.get_popular_videos, + ) + self.get_storage_series = to_raw_response_wrapper( + statistics.get_storage_series, + ) + self.get_stream_series = to_raw_response_wrapper( + statistics.get_stream_series, + ) + self.get_unique_viewers = to_raw_response_wrapper( + statistics.get_unique_viewers, + ) + self.get_unique_viewers_cdn = to_raw_response_wrapper( + statistics.get_unique_viewers_cdn, + ) + self.get_views = to_raw_response_wrapper( + statistics.get_views, + ) + self.get_views_by_browsers = to_raw_response_wrapper( + statistics.get_views_by_browsers, + ) + self.get_views_by_country = to_raw_response_wrapper( + statistics.get_views_by_country, + ) + self.get_views_by_hostname = to_raw_response_wrapper( + statistics.get_views_by_hostname, + ) + self.get_views_by_operating_system = to_raw_response_wrapper( + statistics.get_views_by_operating_system, + ) + self.get_views_by_referer = to_raw_response_wrapper( + statistics.get_views_by_referer, + ) + self.get_views_by_region = to_raw_response_wrapper( + statistics.get_views_by_region, + ) + self.get_views_heatmap = to_raw_response_wrapper( + statistics.get_views_heatmap, + ) + self.get_vod_storage_volume = to_raw_response_wrapper( + statistics.get_vod_storage_volume, + ) + self.get_vod_transcoding_duration = to_raw_response_wrapper( + statistics.get_vod_transcoding_duration, + ) + self.get_vod_unique_viewers_cdn = to_raw_response_wrapper( + statistics.get_vod_unique_viewers_cdn, + ) + self.get_vod_watch_time_cdn = to_raw_response_wrapper( + statistics.get_vod_watch_time_cdn, + ) + self.get_vod_watch_time_total_cdn = to_raw_response_wrapper( + statistics.get_vod_watch_time_total_cdn, + ) + + +class AsyncStatisticsResourceWithRawResponse: + def __init__(self, statistics: AsyncStatisticsResource) -> None: + self._statistics = statistics + + self.get_ffprobes = async_to_raw_response_wrapper( + statistics.get_ffprobes, + ) + self.get_live_unique_viewers = async_to_raw_response_wrapper( + statistics.get_live_unique_viewers, + ) + self.get_live_watch_time_cdn = async_to_raw_response_wrapper( + statistics.get_live_watch_time_cdn, + ) + self.get_live_watch_time_total_cdn = async_to_raw_response_wrapper( + statistics.get_live_watch_time_total_cdn, + ) + self.get_max_streams_series = async_to_raw_response_wrapper( + statistics.get_max_streams_series, + ) + self.get_popular_videos = async_to_raw_response_wrapper( + statistics.get_popular_videos, + ) + self.get_storage_series = async_to_raw_response_wrapper( + statistics.get_storage_series, + ) + self.get_stream_series = async_to_raw_response_wrapper( + statistics.get_stream_series, + ) + self.get_unique_viewers = async_to_raw_response_wrapper( + statistics.get_unique_viewers, + ) + self.get_unique_viewers_cdn = async_to_raw_response_wrapper( + statistics.get_unique_viewers_cdn, + ) + self.get_views = async_to_raw_response_wrapper( + statistics.get_views, + ) + self.get_views_by_browsers = async_to_raw_response_wrapper( + statistics.get_views_by_browsers, + ) + self.get_views_by_country = async_to_raw_response_wrapper( + statistics.get_views_by_country, + ) + self.get_views_by_hostname = async_to_raw_response_wrapper( + statistics.get_views_by_hostname, + ) + self.get_views_by_operating_system = async_to_raw_response_wrapper( + statistics.get_views_by_operating_system, + ) + self.get_views_by_referer = async_to_raw_response_wrapper( + statistics.get_views_by_referer, + ) + self.get_views_by_region = async_to_raw_response_wrapper( + statistics.get_views_by_region, + ) + self.get_views_heatmap = async_to_raw_response_wrapper( + statistics.get_views_heatmap, + ) + self.get_vod_storage_volume = async_to_raw_response_wrapper( + statistics.get_vod_storage_volume, + ) + self.get_vod_transcoding_duration = async_to_raw_response_wrapper( + statistics.get_vod_transcoding_duration, + ) + self.get_vod_unique_viewers_cdn = async_to_raw_response_wrapper( + statistics.get_vod_unique_viewers_cdn, + ) + self.get_vod_watch_time_cdn = async_to_raw_response_wrapper( + statistics.get_vod_watch_time_cdn, + ) + self.get_vod_watch_time_total_cdn = async_to_raw_response_wrapper( + statistics.get_vod_watch_time_total_cdn, + ) + + +class StatisticsResourceWithStreamingResponse: + def __init__(self, statistics: StatisticsResource) -> None: + self._statistics = statistics + + self.get_ffprobes = to_streamed_response_wrapper( + statistics.get_ffprobes, + ) + self.get_live_unique_viewers = to_streamed_response_wrapper( + statistics.get_live_unique_viewers, + ) + self.get_live_watch_time_cdn = to_streamed_response_wrapper( + statistics.get_live_watch_time_cdn, + ) + self.get_live_watch_time_total_cdn = to_streamed_response_wrapper( + statistics.get_live_watch_time_total_cdn, + ) + self.get_max_streams_series = to_streamed_response_wrapper( + statistics.get_max_streams_series, + ) + self.get_popular_videos = to_streamed_response_wrapper( + statistics.get_popular_videos, + ) + self.get_storage_series = to_streamed_response_wrapper( + statistics.get_storage_series, + ) + self.get_stream_series = to_streamed_response_wrapper( + statistics.get_stream_series, + ) + self.get_unique_viewers = to_streamed_response_wrapper( + statistics.get_unique_viewers, + ) + self.get_unique_viewers_cdn = to_streamed_response_wrapper( + statistics.get_unique_viewers_cdn, + ) + self.get_views = to_streamed_response_wrapper( + statistics.get_views, + ) + self.get_views_by_browsers = to_streamed_response_wrapper( + statistics.get_views_by_browsers, + ) + self.get_views_by_country = to_streamed_response_wrapper( + statistics.get_views_by_country, + ) + self.get_views_by_hostname = to_streamed_response_wrapper( + statistics.get_views_by_hostname, + ) + self.get_views_by_operating_system = to_streamed_response_wrapper( + statistics.get_views_by_operating_system, + ) + self.get_views_by_referer = to_streamed_response_wrapper( + statistics.get_views_by_referer, + ) + self.get_views_by_region = to_streamed_response_wrapper( + statistics.get_views_by_region, + ) + self.get_views_heatmap = to_streamed_response_wrapper( + statistics.get_views_heatmap, + ) + self.get_vod_storage_volume = to_streamed_response_wrapper( + statistics.get_vod_storage_volume, + ) + self.get_vod_transcoding_duration = to_streamed_response_wrapper( + statistics.get_vod_transcoding_duration, + ) + self.get_vod_unique_viewers_cdn = to_streamed_response_wrapper( + statistics.get_vod_unique_viewers_cdn, + ) + self.get_vod_watch_time_cdn = to_streamed_response_wrapper( + statistics.get_vod_watch_time_cdn, + ) + self.get_vod_watch_time_total_cdn = to_streamed_response_wrapper( + statistics.get_vod_watch_time_total_cdn, + ) + + +class AsyncStatisticsResourceWithStreamingResponse: + def __init__(self, statistics: AsyncStatisticsResource) -> None: + self._statistics = statistics + + self.get_ffprobes = async_to_streamed_response_wrapper( + statistics.get_ffprobes, + ) + self.get_live_unique_viewers = async_to_streamed_response_wrapper( + statistics.get_live_unique_viewers, + ) + self.get_live_watch_time_cdn = async_to_streamed_response_wrapper( + statistics.get_live_watch_time_cdn, + ) + self.get_live_watch_time_total_cdn = async_to_streamed_response_wrapper( + statistics.get_live_watch_time_total_cdn, + ) + self.get_max_streams_series = async_to_streamed_response_wrapper( + statistics.get_max_streams_series, + ) + self.get_popular_videos = async_to_streamed_response_wrapper( + statistics.get_popular_videos, + ) + self.get_storage_series = async_to_streamed_response_wrapper( + statistics.get_storage_series, + ) + self.get_stream_series = async_to_streamed_response_wrapper( + statistics.get_stream_series, + ) + self.get_unique_viewers = async_to_streamed_response_wrapper( + statistics.get_unique_viewers, + ) + self.get_unique_viewers_cdn = async_to_streamed_response_wrapper( + statistics.get_unique_viewers_cdn, + ) + self.get_views = async_to_streamed_response_wrapper( + statistics.get_views, + ) + self.get_views_by_browsers = async_to_streamed_response_wrapper( + statistics.get_views_by_browsers, + ) + self.get_views_by_country = async_to_streamed_response_wrapper( + statistics.get_views_by_country, + ) + self.get_views_by_hostname = async_to_streamed_response_wrapper( + statistics.get_views_by_hostname, + ) + self.get_views_by_operating_system = async_to_streamed_response_wrapper( + statistics.get_views_by_operating_system, + ) + self.get_views_by_referer = async_to_streamed_response_wrapper( + statistics.get_views_by_referer, + ) + self.get_views_by_region = async_to_streamed_response_wrapper( + statistics.get_views_by_region, + ) + self.get_views_heatmap = async_to_streamed_response_wrapper( + statistics.get_views_heatmap, + ) + self.get_vod_storage_volume = async_to_streamed_response_wrapper( + statistics.get_vod_storage_volume, + ) + self.get_vod_transcoding_duration = async_to_streamed_response_wrapper( + statistics.get_vod_transcoding_duration, + ) + self.get_vod_unique_viewers_cdn = async_to_streamed_response_wrapper( + statistics.get_vod_unique_viewers_cdn, + ) + self.get_vod_watch_time_cdn = async_to_streamed_response_wrapper( + statistics.get_vod_watch_time_cdn, + ) + self.get_vod_watch_time_total_cdn = async_to_streamed_response_wrapper( + statistics.get_vod_watch_time_total_cdn, + ) diff --git a/src/gcore/resources/streaming/streaming.py b/src/gcore/resources/streaming/streaming.py new file mode 100644 index 00000000..11e18d2b --- /dev/null +++ b/src/gcore/resources/streaming/streaming.py @@ -0,0 +1,390 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .players import ( + PlayersResource, + AsyncPlayersResource, + PlayersResourceWithRawResponse, + AsyncPlayersResourceWithRawResponse, + PlayersResourceWithStreamingResponse, + AsyncPlayersResourceWithStreamingResponse, +) +from .ai_tasks import ( + AITasksResource, + AsyncAITasksResource, + AITasksResourceWithRawResponse, + AsyncAITasksResourceWithRawResponse, + AITasksResourceWithStreamingResponse, + AsyncAITasksResourceWithStreamingResponse, +) +from ..._compat import cached_property +from .playlists import ( + PlaylistsResource, + AsyncPlaylistsResource, + PlaylistsResourceWithRawResponse, + AsyncPlaylistsResourceWithRawResponse, + PlaylistsResourceWithStreamingResponse, + AsyncPlaylistsResourceWithStreamingResponse, +) +from .restreams import ( + RestreamsResource, + AsyncRestreamsResource, + RestreamsResourceWithRawResponse, + AsyncRestreamsResourceWithRawResponse, + RestreamsResourceWithStreamingResponse, + AsyncRestreamsResourceWithStreamingResponse, +) +from .broadcasts import ( + BroadcastsResource, + AsyncBroadcastsResource, + BroadcastsResourceWithRawResponse, + AsyncBroadcastsResourceWithRawResponse, + BroadcastsResourceWithStreamingResponse, + AsyncBroadcastsResourceWithStreamingResponse, +) +from .statistics import ( + StatisticsResource, + AsyncStatisticsResource, + StatisticsResourceWithRawResponse, + AsyncStatisticsResourceWithRawResponse, + StatisticsResourceWithStreamingResponse, + AsyncStatisticsResourceWithStreamingResponse, +) +from ..._resource import SyncAPIResource, AsyncAPIResource +from .directories import ( + DirectoriesResource, + AsyncDirectoriesResource, + DirectoriesResourceWithRawResponse, + AsyncDirectoriesResourceWithRawResponse, + DirectoriesResourceWithStreamingResponse, + AsyncDirectoriesResourceWithStreamingResponse, +) +from .quality_sets import ( + QualitySetsResource, + AsyncQualitySetsResource, + QualitySetsResourceWithRawResponse, + AsyncQualitySetsResourceWithRawResponse, + QualitySetsResourceWithStreamingResponse, + AsyncQualitySetsResourceWithStreamingResponse, +) +from .videos.videos import ( + VideosResource, + AsyncVideosResource, + VideosResourceWithRawResponse, + AsyncVideosResourceWithRawResponse, + VideosResourceWithStreamingResponse, + AsyncVideosResourceWithStreamingResponse, +) +from .streams.streams import ( + StreamsResource, + AsyncStreamsResource, + StreamsResourceWithRawResponse, + AsyncStreamsResourceWithRawResponse, + StreamsResourceWithStreamingResponse, + AsyncStreamsResourceWithStreamingResponse, +) + +__all__ = ["StreamingResource", "AsyncStreamingResource"] + + +class StreamingResource(SyncAPIResource): + @cached_property + def ai_tasks(self) -> AITasksResource: + return AITasksResource(self._client) + + @cached_property + def broadcasts(self) -> BroadcastsResource: + return BroadcastsResource(self._client) + + @cached_property + def directories(self) -> DirectoriesResource: + return DirectoriesResource(self._client) + + @cached_property + def players(self) -> PlayersResource: + return PlayersResource(self._client) + + @cached_property + def quality_sets(self) -> QualitySetsResource: + return QualitySetsResource(self._client) + + @cached_property + def playlists(self) -> PlaylistsResource: + return PlaylistsResource(self._client) + + @cached_property + def videos(self) -> VideosResource: + return VideosResource(self._client) + + @cached_property + def streams(self) -> StreamsResource: + return StreamsResource(self._client) + + @cached_property + def restreams(self) -> RestreamsResource: + return RestreamsResource(self._client) + + @cached_property + def statistics(self) -> StatisticsResource: + return StatisticsResource(self._client) + + @cached_property + def with_raw_response(self) -> StreamingResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return StreamingResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> StreamingResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return StreamingResourceWithStreamingResponse(self) + + +class AsyncStreamingResource(AsyncAPIResource): + @cached_property + def ai_tasks(self) -> AsyncAITasksResource: + return AsyncAITasksResource(self._client) + + @cached_property + def broadcasts(self) -> AsyncBroadcastsResource: + return AsyncBroadcastsResource(self._client) + + @cached_property + def directories(self) -> AsyncDirectoriesResource: + return AsyncDirectoriesResource(self._client) + + @cached_property + def players(self) -> AsyncPlayersResource: + return AsyncPlayersResource(self._client) + + @cached_property + def quality_sets(self) -> AsyncQualitySetsResource: + return AsyncQualitySetsResource(self._client) + + @cached_property + def playlists(self) -> AsyncPlaylistsResource: + return AsyncPlaylistsResource(self._client) + + @cached_property + def videos(self) -> AsyncVideosResource: + return AsyncVideosResource(self._client) + + @cached_property + def streams(self) -> AsyncStreamsResource: + return AsyncStreamsResource(self._client) + + @cached_property + def restreams(self) -> AsyncRestreamsResource: + return AsyncRestreamsResource(self._client) + + @cached_property + def statistics(self) -> AsyncStatisticsResource: + return AsyncStatisticsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncStreamingResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncStreamingResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncStreamingResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncStreamingResourceWithStreamingResponse(self) + + +class StreamingResourceWithRawResponse: + def __init__(self, streaming: StreamingResource) -> None: + self._streaming = streaming + + @cached_property + def ai_tasks(self) -> AITasksResourceWithRawResponse: + return AITasksResourceWithRawResponse(self._streaming.ai_tasks) + + @cached_property + def broadcasts(self) -> BroadcastsResourceWithRawResponse: + return BroadcastsResourceWithRawResponse(self._streaming.broadcasts) + + @cached_property + def directories(self) -> DirectoriesResourceWithRawResponse: + return DirectoriesResourceWithRawResponse(self._streaming.directories) + + @cached_property + def players(self) -> PlayersResourceWithRawResponse: + return PlayersResourceWithRawResponse(self._streaming.players) + + @cached_property + def quality_sets(self) -> QualitySetsResourceWithRawResponse: + return QualitySetsResourceWithRawResponse(self._streaming.quality_sets) + + @cached_property + def playlists(self) -> PlaylistsResourceWithRawResponse: + return PlaylistsResourceWithRawResponse(self._streaming.playlists) + + @cached_property + def videos(self) -> VideosResourceWithRawResponse: + return VideosResourceWithRawResponse(self._streaming.videos) + + @cached_property + def streams(self) -> StreamsResourceWithRawResponse: + return StreamsResourceWithRawResponse(self._streaming.streams) + + @cached_property + def restreams(self) -> RestreamsResourceWithRawResponse: + return RestreamsResourceWithRawResponse(self._streaming.restreams) + + @cached_property + def statistics(self) -> StatisticsResourceWithRawResponse: + return StatisticsResourceWithRawResponse(self._streaming.statistics) + + +class AsyncStreamingResourceWithRawResponse: + def __init__(self, streaming: AsyncStreamingResource) -> None: + self._streaming = streaming + + @cached_property + def ai_tasks(self) -> AsyncAITasksResourceWithRawResponse: + return AsyncAITasksResourceWithRawResponse(self._streaming.ai_tasks) + + @cached_property + def broadcasts(self) -> AsyncBroadcastsResourceWithRawResponse: + return AsyncBroadcastsResourceWithRawResponse(self._streaming.broadcasts) + + @cached_property + def directories(self) -> AsyncDirectoriesResourceWithRawResponse: + return AsyncDirectoriesResourceWithRawResponse(self._streaming.directories) + + @cached_property + def players(self) -> AsyncPlayersResourceWithRawResponse: + return AsyncPlayersResourceWithRawResponse(self._streaming.players) + + @cached_property + def quality_sets(self) -> AsyncQualitySetsResourceWithRawResponse: + return AsyncQualitySetsResourceWithRawResponse(self._streaming.quality_sets) + + @cached_property + def playlists(self) -> AsyncPlaylistsResourceWithRawResponse: + return AsyncPlaylistsResourceWithRawResponse(self._streaming.playlists) + + @cached_property + def videos(self) -> AsyncVideosResourceWithRawResponse: + return AsyncVideosResourceWithRawResponse(self._streaming.videos) + + @cached_property + def streams(self) -> AsyncStreamsResourceWithRawResponse: + return AsyncStreamsResourceWithRawResponse(self._streaming.streams) + + @cached_property + def restreams(self) -> AsyncRestreamsResourceWithRawResponse: + return AsyncRestreamsResourceWithRawResponse(self._streaming.restreams) + + @cached_property + def statistics(self) -> AsyncStatisticsResourceWithRawResponse: + return AsyncStatisticsResourceWithRawResponse(self._streaming.statistics) + + +class StreamingResourceWithStreamingResponse: + def __init__(self, streaming: StreamingResource) -> None: + self._streaming = streaming + + @cached_property + def ai_tasks(self) -> AITasksResourceWithStreamingResponse: + return AITasksResourceWithStreamingResponse(self._streaming.ai_tasks) + + @cached_property + def broadcasts(self) -> BroadcastsResourceWithStreamingResponse: + return BroadcastsResourceWithStreamingResponse(self._streaming.broadcasts) + + @cached_property + def directories(self) -> DirectoriesResourceWithStreamingResponse: + return DirectoriesResourceWithStreamingResponse(self._streaming.directories) + + @cached_property + def players(self) -> PlayersResourceWithStreamingResponse: + return PlayersResourceWithStreamingResponse(self._streaming.players) + + @cached_property + def quality_sets(self) -> QualitySetsResourceWithStreamingResponse: + return QualitySetsResourceWithStreamingResponse(self._streaming.quality_sets) + + @cached_property + def playlists(self) -> PlaylistsResourceWithStreamingResponse: + return PlaylistsResourceWithStreamingResponse(self._streaming.playlists) + + @cached_property + def videos(self) -> VideosResourceWithStreamingResponse: + return VideosResourceWithStreamingResponse(self._streaming.videos) + + @cached_property + def streams(self) -> StreamsResourceWithStreamingResponse: + return StreamsResourceWithStreamingResponse(self._streaming.streams) + + @cached_property + def restreams(self) -> RestreamsResourceWithStreamingResponse: + return RestreamsResourceWithStreamingResponse(self._streaming.restreams) + + @cached_property + def statistics(self) -> StatisticsResourceWithStreamingResponse: + return StatisticsResourceWithStreamingResponse(self._streaming.statistics) + + +class AsyncStreamingResourceWithStreamingResponse: + def __init__(self, streaming: AsyncStreamingResource) -> None: + self._streaming = streaming + + @cached_property + def ai_tasks(self) -> AsyncAITasksResourceWithStreamingResponse: + return AsyncAITasksResourceWithStreamingResponse(self._streaming.ai_tasks) + + @cached_property + def broadcasts(self) -> AsyncBroadcastsResourceWithStreamingResponse: + return AsyncBroadcastsResourceWithStreamingResponse(self._streaming.broadcasts) + + @cached_property + def directories(self) -> AsyncDirectoriesResourceWithStreamingResponse: + return AsyncDirectoriesResourceWithStreamingResponse(self._streaming.directories) + + @cached_property + def players(self) -> AsyncPlayersResourceWithStreamingResponse: + return AsyncPlayersResourceWithStreamingResponse(self._streaming.players) + + @cached_property + def quality_sets(self) -> AsyncQualitySetsResourceWithStreamingResponse: + return AsyncQualitySetsResourceWithStreamingResponse(self._streaming.quality_sets) + + @cached_property + def playlists(self) -> AsyncPlaylistsResourceWithStreamingResponse: + return AsyncPlaylistsResourceWithStreamingResponse(self._streaming.playlists) + + @cached_property + def videos(self) -> AsyncVideosResourceWithStreamingResponse: + return AsyncVideosResourceWithStreamingResponse(self._streaming.videos) + + @cached_property + def streams(self) -> AsyncStreamsResourceWithStreamingResponse: + return AsyncStreamsResourceWithStreamingResponse(self._streaming.streams) + + @cached_property + def restreams(self) -> AsyncRestreamsResourceWithStreamingResponse: + return AsyncRestreamsResourceWithStreamingResponse(self._streaming.restreams) + + @cached_property + def statistics(self) -> AsyncStatisticsResourceWithStreamingResponse: + return AsyncStatisticsResourceWithStreamingResponse(self._streaming.statistics) diff --git a/src/gcore/resources/streaming/streams/__init__.py b/src/gcore/resources/streaming/streams/__init__.py new file mode 100644 index 00000000..49461963 --- /dev/null +++ b/src/gcore/resources/streaming/streams/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .streams import ( + StreamsResource, + AsyncStreamsResource, + StreamsResourceWithRawResponse, + AsyncStreamsResourceWithRawResponse, + StreamsResourceWithStreamingResponse, + AsyncStreamsResourceWithStreamingResponse, +) +from .overlays import ( + OverlaysResource, + AsyncOverlaysResource, + OverlaysResourceWithRawResponse, + AsyncOverlaysResourceWithRawResponse, + OverlaysResourceWithStreamingResponse, + AsyncOverlaysResourceWithStreamingResponse, +) + +__all__ = [ + "OverlaysResource", + "AsyncOverlaysResource", + "OverlaysResourceWithRawResponse", + "AsyncOverlaysResourceWithRawResponse", + "OverlaysResourceWithStreamingResponse", + "AsyncOverlaysResourceWithStreamingResponse", + "StreamsResource", + "AsyncStreamsResource", + "StreamsResourceWithRawResponse", + "AsyncStreamsResourceWithRawResponse", + "StreamsResourceWithStreamingResponse", + "AsyncStreamsResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/streaming/streams/overlays.py b/src/gcore/resources/streaming/streams/overlays.py new file mode 100644 index 00000000..780f045b --- /dev/null +++ b/src/gcore/resources/streaming/streams/overlays.py @@ -0,0 +1,732 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.streaming.streams import overlay_create_params, overlay_update_params, overlay_update_multiple_params +from ....types.streaming.streams.overlay import Overlay +from ....types.streaming.streams.overlay_list_response import OverlayListResponse +from ....types.streaming.streams.overlay_create_response import OverlayCreateResponse +from ....types.streaming.streams.overlay_update_multiple_response import OverlayUpdateMultipleResponse + +__all__ = ["OverlaysResource", "AsyncOverlaysResource"] + + +class OverlaysResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> OverlaysResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return OverlaysResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> OverlaysResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return OverlaysResourceWithStreamingResponse(self) + + def create( + self, + stream_id: int, + *, + body: Iterable[overlay_create_params.Body] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverlayCreateResponse: + """ + "Overlay" is a live HTML widget, which rendered and inserted over the live + stream. + + There are can be more that 1 overlay over a stream, which are small or stretched + over full frame. Overlays can have transparent areas. Frequency of update is 1 + FPS. Automatic size scaling for Adaptative Bitrate qualities is applied. + + ![HTML Overlays](https://demo-files.gvideo.io/apidocs/coffee_run_overlays.gif) + + How to activate and use in simple steps: + + - Activate feature on your account, ask the Support Team + - Set “`html_overlay`” attribute to "true" for a stream + - Set array of overlays + - Start or restart your stream again + - Enjoy :-) + + For the first time an overlay should be enabled **before** start pushing of a + live stream. If you are pushing the stream already (stream is alive and you are + activating overlay for the first time), then overlay will become active after + restart pushing. + + Once you activate the overlay for the stream for the first time, you can add, + change, move, delete widgets on the fly even during a live stream with no + affection on a result stream. + + Tech limits: + + - Max original stream resolution = FullHD. + - It is necessary that all widgets must fit into the original frame of the + source stream (width x height). If one of the widgets does not fit into the + original frame, for example, goes 1 pixel beyond the frame, then all widgets + will be hidden. + - Attributes of overlays: + - url – should be valid http/https url + - 0 < width <= 1920 + - 0 < height <= 1080 + - 0 <= x < 1920 + - 0 <= y < 1080 + - stretch – stretch to full frame. Cannot be used with positioning attributes. + - HTML widget can be access by HTTP 80 or HTTPS 443 ports. + - HTML page code at the "url" link is read once when starting the stream only. + For dynamically updating widgets, you must use either dynamic code via + JavaScript or cause a page refresh via HTML meta tag + . + - Widgets can contain scripts, but they must be lightweight and using small + amount memory, CPU, and bandwidth. It is prohibited to run heavy scripts, + create a heavy load on the network, or run other heavy modules. Such widgets + can be stopped automatically, and the ability to insert widgets itself is + banned. + - If feature is disabled, you will receive HTTP code: 422. Error text: Feature + disabled. Contact support to enable. + + Please, pay attention to the content of HTML widges you use. If you don't trust + them, then you shouldn't use them, as their result will be displayed in live + stream to all users. + + **Will there be a widget in the recording?** Right now overlay widgets are sent + to the end viewer in the HLS/DASH streams, but are not recorded due to technical + limitations. We are working to ensure that widgets remain in the recordings as + well. Follow the news. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/streaming/streams/{stream_id}/overlays", + body=maybe_transform(body, Iterable[overlay_create_params.Body]), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverlayCreateResponse, + ) + + def update( + self, + overlay_id: int, + *, + stream_id: int, + height: int | Omit = omit, + stretch: bool | Omit = omit, + url: str | Omit = omit, + width: int | Omit = omit, + x: int | Omit = omit, + y: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Overlay: + """ + Updates overlay settings + + Args: + height: Height of the widget + + stretch: Switch of auto scaling the widget. Must not be used as "true" simultaneously + with the coordinate installation method (w, h, x, y). + + url: Valid http/https URL to an HTML page/widget + + width: Width of the widget + + x: Coordinate of left upper corner + + y: Coordinate of left upper corner + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/streaming/streams/{stream_id}/overlays/{overlay_id}", + body=maybe_transform( + { + "height": height, + "stretch": stretch, + "url": url, + "width": width, + "x": x, + "y": y, + }, + overlay_update_params.OverlayUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Overlay, + ) + + def list( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverlayListResponse: + """ + Returns a list of HTML overlay widgets which are attached to a stream + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/streams/{stream_id}/overlays", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverlayListResponse, + ) + + def delete( + self, + overlay_id: int, + *, + stream_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete an overlay + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/streaming/streams/{stream_id}/overlays/{overlay_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + overlay_id: int, + *, + stream_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Overlay: + """ + Get overlay details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/streams/{stream_id}/overlays/{overlay_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Overlay, + ) + + def update_multiple( + self, + stream_id: int, + *, + body: Iterable[overlay_update_multiple_params.Body] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverlayUpdateMultipleResponse: + """ + Updates settings for set of overlays + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/streaming/streams/{stream_id}/overlays", + body=maybe_transform(body, Iterable[overlay_update_multiple_params.Body]), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverlayUpdateMultipleResponse, + ) + + +class AsyncOverlaysResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncOverlaysResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncOverlaysResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncOverlaysResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncOverlaysResourceWithStreamingResponse(self) + + async def create( + self, + stream_id: int, + *, + body: Iterable[overlay_create_params.Body] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverlayCreateResponse: + """ + "Overlay" is a live HTML widget, which rendered and inserted over the live + stream. + + There are can be more that 1 overlay over a stream, which are small or stretched + over full frame. Overlays can have transparent areas. Frequency of update is 1 + FPS. Automatic size scaling for Adaptative Bitrate qualities is applied. + + ![HTML Overlays](https://demo-files.gvideo.io/apidocs/coffee_run_overlays.gif) + + How to activate and use in simple steps: + + - Activate feature on your account, ask the Support Team + - Set “`html_overlay`” attribute to "true" for a stream + - Set array of overlays + - Start or restart your stream again + - Enjoy :-) + + For the first time an overlay should be enabled **before** start pushing of a + live stream. If you are pushing the stream already (stream is alive and you are + activating overlay for the first time), then overlay will become active after + restart pushing. + + Once you activate the overlay for the stream for the first time, you can add, + change, move, delete widgets on the fly even during a live stream with no + affection on a result stream. + + Tech limits: + + - Max original stream resolution = FullHD. + - It is necessary that all widgets must fit into the original frame of the + source stream (width x height). If one of the widgets does not fit into the + original frame, for example, goes 1 pixel beyond the frame, then all widgets + will be hidden. + - Attributes of overlays: + - url – should be valid http/https url + - 0 < width <= 1920 + - 0 < height <= 1080 + - 0 <= x < 1920 + - 0 <= y < 1080 + - stretch – stretch to full frame. Cannot be used with positioning attributes. + - HTML widget can be access by HTTP 80 or HTTPS 443 ports. + - HTML page code at the "url" link is read once when starting the stream only. + For dynamically updating widgets, you must use either dynamic code via + JavaScript or cause a page refresh via HTML meta tag + . + - Widgets can contain scripts, but they must be lightweight and using small + amount memory, CPU, and bandwidth. It is prohibited to run heavy scripts, + create a heavy load on the network, or run other heavy modules. Such widgets + can be stopped automatically, and the ability to insert widgets itself is + banned. + - If feature is disabled, you will receive HTTP code: 422. Error text: Feature + disabled. Contact support to enable. + + Please, pay attention to the content of HTML widges you use. If you don't trust + them, then you shouldn't use them, as their result will be displayed in live + stream to all users. + + **Will there be a widget in the recording?** Right now overlay widgets are sent + to the end viewer in the HLS/DASH streams, but are not recorded due to technical + limitations. We are working to ensure that widgets remain in the recordings as + well. Follow the news. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/streaming/streams/{stream_id}/overlays", + body=await async_maybe_transform(body, Iterable[overlay_create_params.Body]), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverlayCreateResponse, + ) + + async def update( + self, + overlay_id: int, + *, + stream_id: int, + height: int | Omit = omit, + stretch: bool | Omit = omit, + url: str | Omit = omit, + width: int | Omit = omit, + x: int | Omit = omit, + y: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Overlay: + """ + Updates overlay settings + + Args: + height: Height of the widget + + stretch: Switch of auto scaling the widget. Must not be used as "true" simultaneously + with the coordinate installation method (w, h, x, y). + + url: Valid http/https URL to an HTML page/widget + + width: Width of the widget + + x: Coordinate of left upper corner + + y: Coordinate of left upper corner + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/streaming/streams/{stream_id}/overlays/{overlay_id}", + body=await async_maybe_transform( + { + "height": height, + "stretch": stretch, + "url": url, + "width": width, + "x": x, + "y": y, + }, + overlay_update_params.OverlayUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Overlay, + ) + + async def list( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverlayListResponse: + """ + Returns a list of HTML overlay widgets which are attached to a stream + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/streams/{stream_id}/overlays", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverlayListResponse, + ) + + async def delete( + self, + overlay_id: int, + *, + stream_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete an overlay + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/streaming/streams/{stream_id}/overlays/{overlay_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + overlay_id: int, + *, + stream_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Overlay: + """ + Get overlay details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/streams/{stream_id}/overlays/{overlay_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Overlay, + ) + + async def update_multiple( + self, + stream_id: int, + *, + body: Iterable[overlay_update_multiple_params.Body] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OverlayUpdateMultipleResponse: + """ + Updates settings for set of overlays + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/streaming/streams/{stream_id}/overlays", + body=await async_maybe_transform(body, Iterable[overlay_update_multiple_params.Body]), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OverlayUpdateMultipleResponse, + ) + + +class OverlaysResourceWithRawResponse: + def __init__(self, overlays: OverlaysResource) -> None: + self._overlays = overlays + + self.create = to_raw_response_wrapper( + overlays.create, + ) + self.update = to_raw_response_wrapper( + overlays.update, + ) + self.list = to_raw_response_wrapper( + overlays.list, + ) + self.delete = to_raw_response_wrapper( + overlays.delete, + ) + self.get = to_raw_response_wrapper( + overlays.get, + ) + self.update_multiple = to_raw_response_wrapper( + overlays.update_multiple, + ) + + +class AsyncOverlaysResourceWithRawResponse: + def __init__(self, overlays: AsyncOverlaysResource) -> None: + self._overlays = overlays + + self.create = async_to_raw_response_wrapper( + overlays.create, + ) + self.update = async_to_raw_response_wrapper( + overlays.update, + ) + self.list = async_to_raw_response_wrapper( + overlays.list, + ) + self.delete = async_to_raw_response_wrapper( + overlays.delete, + ) + self.get = async_to_raw_response_wrapper( + overlays.get, + ) + self.update_multiple = async_to_raw_response_wrapper( + overlays.update_multiple, + ) + + +class OverlaysResourceWithStreamingResponse: + def __init__(self, overlays: OverlaysResource) -> None: + self._overlays = overlays + + self.create = to_streamed_response_wrapper( + overlays.create, + ) + self.update = to_streamed_response_wrapper( + overlays.update, + ) + self.list = to_streamed_response_wrapper( + overlays.list, + ) + self.delete = to_streamed_response_wrapper( + overlays.delete, + ) + self.get = to_streamed_response_wrapper( + overlays.get, + ) + self.update_multiple = to_streamed_response_wrapper( + overlays.update_multiple, + ) + + +class AsyncOverlaysResourceWithStreamingResponse: + def __init__(self, overlays: AsyncOverlaysResource) -> None: + self._overlays = overlays + + self.create = async_to_streamed_response_wrapper( + overlays.create, + ) + self.update = async_to_streamed_response_wrapper( + overlays.update, + ) + self.list = async_to_streamed_response_wrapper( + overlays.list, + ) + self.delete = async_to_streamed_response_wrapper( + overlays.delete, + ) + self.get = async_to_streamed_response_wrapper( + overlays.get, + ) + self.update_multiple = async_to_streamed_response_wrapper( + overlays.update_multiple, + ) diff --git a/src/gcore/resources/streaming/streams/streams.py b/src/gcore/resources/streaming/streams/streams.py new file mode 100644 index 00000000..5fc4b7c5 --- /dev/null +++ b/src/gcore/resources/streaming/streams/streams.py @@ -0,0 +1,1678 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal + +import httpx + +from .overlays import ( + OverlaysResource, + AsyncOverlaysResource, + OverlaysResourceWithRawResponse, + AsyncOverlaysResourceWithRawResponse, + OverlaysResourceWithStreamingResponse, + AsyncOverlaysResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncPageStreaming, AsyncPageStreaming +from ...._base_client import AsyncPaginator, make_request_options +from ....types.streaming import ( + stream_list_params, + stream_create_params, + stream_update_params, + stream_create_clip_params, +) +from ....types.streaming.clip import Clip +from ....types.streaming.video import Video +from ....types.streaming.stream import Stream +from ....types.streaming.stream_list_clips_response import StreamListClipsResponse +from ....types.streaming.stream_start_recording_response import StreamStartRecordingResponse + +__all__ = ["StreamsResource", "AsyncStreamsResource"] + + +class StreamsResource(SyncAPIResource): + @cached_property + def overlays(self) -> OverlaysResource: + return OverlaysResource(self._client) + + @cached_property + def with_raw_response(self) -> StreamsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return StreamsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> StreamsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return StreamsResourceWithStreamingResponse(self) + + def create( + self, + *, + name: str, + active: bool | Omit = omit, + auto_record: bool | Omit = omit, + broadcast_ids: Iterable[int] | Omit = omit, + cdn_id: int | Omit = omit, + client_entity_data: str | Omit = omit, + client_user_id: int | Omit = omit, + dvr_duration: int | Omit = omit, + dvr_enabled: bool | Omit = omit, + hls_mpegts_endlist_tag: bool | Omit = omit, + html_overlay: bool | Omit = omit, + projection: Literal["regular", "vr360", "vr180", "vr360tb"] | Omit = omit, + pull: bool | Omit = omit, + quality_set_id: int | Omit = omit, + record_type: Literal["origin", "transcoded"] | Omit = omit, + uri: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Stream: + """ + Use this method to create a new live stream entity for broadcasting. + + The input in API may contain streams of different formats, including the most + common ones RTMP, RTMPS, SRT, HLS. Note that multicast MPEG-TS over UDP and + others are supported too, ask the Support Team please. + + For ingestion, you can use both PUSH and PULL methods. + + Also you can use the main and backup servers, which are geographically located + in different locations. By default, any free ingest points in the world are + used. Settings have been applied that deliver low-latency streams in the optimal + way. If for some reason you need to set a fixed ingest point, or if you need to + set the main and backup ingest points in the same region (for example, do not + send streams outside the EU or US), then contact our Support Team. + + The output is HLS and MPEG-DASH with ABR. We transcode video for you by our + cloud-based infrastructure. ABR ladder supports all qualities from SD to 8K HDR + 60fps. + + All our streams are Low Latency enabled. We support a delay of ±4 seconds for + video streams by utilizing Common Media Application Format (CMAF) technology. So + you obtain latency from the traditional 30-50 seconds to ±4 seconds only by + default. If you need legacy non-low-latency HLS, then look at HLS MPEG-TS + delivery below. + + You have access to additional functions such as: + + - DVR + - Recording + - Live clipping + - Restreaming + - (soon) AI Automatic Speech Recognition for subtitles/captions generating + + For more information see specific API methods, and the Knowledge Base. + + ![HTML Overlays](https://demo-files.gvideo.io/apidocs/low-latency-football.gif) + + Args: + name: Stream name. + + Often used as a human-readable name for the stream, but can contain any text you + wish. The values are not unique and may be repeated. + + Examples: + + - Conference in July + - Stream #10003 + - Open-Air Camera #31 Backstage + - 480fd499-2de2-4988-bc1a-a4eebe9818ee + + active: Stream switch between on and off. This is not an indicator of the status "stream + is receiving and it is LIVE", but rather an on/off switch. + + When stream is switched off, there is no way to process it: PULL is deactivated + and PUSH will return an error. + + - true – stream can be processed + - false – stream is off, and cannot be processed + + auto_record: Enables autotomatic recording of the stream when it started. So you don't need + to call recording manually. + + Result of recording is automatically added to video hosting. For details see the + /streams/`start_recording` method and in knowledge base + + Values: + + - true – auto recording is enabled + - false – auto recording is disabled + + broadcast_ids: IDs of broadcasts which will include this stream + + cdn_id: ID of custom CDN resource from which the content will be delivered (only if you + know what you do) + + client_entity_data: Custom meta field designed to store your own extra information about a video + entity: video source, video id, parameters, etc. We do not use this field in any + way when processing the stream. You can store any data in any format (string, + json, etc), saved as a text string. Example: + `client_entity_data = '{ "seq_id": "1234567890", "name": "John Doe", "iat": 1516239022 }'` + + client_user_id: Custom meta field for storing the Identifier in your system. We do not use this + field in any way when processing the stream. Example: `client_user_id = 1001` + + dvr_duration: DVR duration in seconds if DVR feature is enabled for the stream. So this is + duration of how far the user can rewind the live stream. + + `dvr_duration` range is [30...14400]. + + Maximum value is 4 hours = 14400 seconds. If you need more, ask the Support Team + please. + + dvr_enabled: + Enables DVR for the stream: + + - true – DVR is enabled + - false – DVR is disabled + + hls_mpegts_endlist_tag: Add `#EXT-X-ENDLIST` tag within .m3u8 playlist after the last segment of a live + stream when broadcast is ended. + + html_overlay: Switch on mode to insert and display real-time HTML overlay widgets on top of + live streams + + projection: Visualization mode for 360° streams, how the stream is rendered in our web + player ONLY. If you would like to show video 360° in an external video player, + then use parameters of that video player. + + Modes: + + - regular – regular “flat” stream + - vr360 – display stream in 360° mode + - vr180 – display stream in 180° mode + - vr360tb – display stream in 3D 360° mode Top-Bottom + + pull: Indicates if stream is pulled from external server or not. Has two possible + values: + + - true – stream is received by PULL method. Use this when need to get stream + from external server. + - false – stream is received by PUSH method. Use this when need to send stream + from end-device to our Streaming Platform, i.e. from your encoder, mobile app + or OBS Studio. + + quality_set_id: Custom quality set ID for transcoding, if transcoding is required according to + your conditions. Look at GET /`quality_sets` method + + record_type: Method of recording a stream. Specifies the source from which the stream will be + recorded: original or transcoded. + + Types: + + - "origin" – To record RMTP/SRT/etc original clean media source. + - "transcoded" – To record the output transcoded version of the stream, + including overlays, texts, logos, etc. additional media layers. + + uri: When using PULL method, this is the URL to pull a stream from. + + You can specify multiple addresses separated by a space (" "), so you can + organize a backup plan. In this case, the specified addresses will be selected + one by one using round robin scheduling. If the first address does not respond, + then the next one in the list will be automatically requested, returning to the + first and so on in a circle. Also, if the sucessfully working stream stops + sending data, then the next one will be selected according to the same scheme. + + After 2 hours of inactivity of your original stream, the system stops PULL + requests and the stream is deactivated (the "active" field switches to "false"). + + Please, note that this field is for PULL only, so is not suitable for PUSH. Look + at fields "push_url" and "push_url_srt" from GET method. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/streaming/streams", + body=maybe_transform( + { + "name": name, + "active": active, + "auto_record": auto_record, + "broadcast_ids": broadcast_ids, + "cdn_id": cdn_id, + "client_entity_data": client_entity_data, + "client_user_id": client_user_id, + "dvr_duration": dvr_duration, + "dvr_enabled": dvr_enabled, + "hls_mpegts_endlist_tag": hls_mpegts_endlist_tag, + "html_overlay": html_overlay, + "projection": projection, + "pull": pull, + "quality_set_id": quality_set_id, + "record_type": record_type, + "uri": uri, + }, + stream_create_params.StreamCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Stream, + ) + + def update( + self, + stream_id: int, + *, + stream: stream_update_params.Stream | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Stream: + """ + Updates stream settings + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/streaming/streams/{stream_id}", + body=maybe_transform({"stream": stream}, stream_update_params.StreamUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Stream, + ) + + def list( + self, + *, + page: int | Omit = omit, + with_broadcasts: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncPageStreaming[Stream]: + """Returns a list of streams + + Args: + page: Query parameter. + + Use it to list the paginated content + + with_broadcasts: Query parameter. Set to 1 to get details of the broadcasts associated with the + stream + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/streams", + page=SyncPageStreaming[Stream], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "page": page, + "with_broadcasts": with_broadcasts, + }, + stream_list_params.StreamListParams, + ), + ), + model=Stream, + ) + + def delete( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a live stream. + + After deleting the live stream, all associated data is deleted: settings, PUSH + and PULL links, video playback links, etc. + + Live stream information is deleted permanently and irreversibly. Therefore, it + is impossible to restore data and files after this. + + But if the live had recordings, they continue to remain independent Video + entities. The "stream_id" parameter will simply point to a stream that no longer + exists. + + Perhaps, instead of deleting, you may use the stream deactivation: + + ``` + PATCH / videos / {stream_id} + {"active": false} + ``` + + For details, see the Product Documentation. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/streaming/streams/{stream_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def clear_dvr( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Clear live stream DVR + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._put( + f"/streaming/streams/{stream_id}/dvr_cleanup", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def create_clip( + self, + stream_id: int, + *, + duration: int, + expiration: int | Omit = omit, + start: int | Omit = omit, + vod_required: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Clip: + """ + Create an instant clip from on-going live stream. + + Instant clips are applicable in cases where there is no time to wait for the + broadcast to be completed and recorded. For example, for quickly cutting + highlights in sport events, or cutting an important moment in the news or live + performance. + + DVR function must be enabled for clip recording. If the DVR is disabled, the + response will be error 422. + + Instant clip becomes available for viewing in the following formats: + + - HLS .m3u8, + - MP4, + - VOD in video hosting with a permanent link to watch video. + + ![HTML Overlays](https://demo-files.gvideo.io/apidocs/clip_recording_mp4_hls.gif) + + **Clip lifetime:** + + Instant clips are a copy of the stream, created from a live stream. They are + stored in memory for a limited time, after which the clip ceases to exist and + you will receive a 404 on the link. + + Limits that you should keep in mind: + + - The clip's lifespan is controlled by `expiration` parameter. + - The default expiration value is 1 hour. The value can be set from 1 minute to + 4 hours. + - If you want a video for longer or permanent viewing, then create a regular VOD + based on the clip. This way you can use the clip's link for the first time, + and immediately after the transcoded version is ready, you can change by + yourself it to a permanent link of VOD. + - The clip becomes available only after it is completely copied from the live + stream. So the clip will be available after `start + duration` exact time. If + you try to request it before this time, the response will be error code 425 + "Too Early". + + **Cutting a clip from a source:** + + In order to use clips recording feature, DVR must be enabled for a stream: + "dvr_enabled: true". The DVR serves as a source for creating clips: + + - By default live stream DVR is set to 1 hour (3600 seconds). You can create an + instant clip using any segment of this time period by specifying the desired + start time and duration. + - If you create a clip, but the DVR expires, the clip will still exist for the + specified time as a copy of the stream. + + **Getting permanent VOD:** + + To get permanent VOD version of a live clip use this parameter when making a + request to create a clip: `vod_required: true`. + + Later, when the clip is ready, grab `video_id` value from the response and query + the video by regular GET /video/{id} method. + + Args: + duration: Requested segment duration in seconds to be cut. + + Please, note that cutting is based on the idea of instantly creating a clip, + instead of precise timing. So final segment may be: + + - Less than the specified value if there is less data in the DVR than the + requested segment. + - Greater than the specified value, because segment is aligned to the first and + last key frames of already stored fragment in DVR, this way -1 and +1 chunks + can be added to left and right. + + Duration of cutted segment cannot be greater than DVR duration for this stream. + Therefore, to change the maximum, use "dvr_duration" parameter of this stream. + + expiration: Expire time of the clip via a public link. + + Unix timestamp in seconds, absolute value. + + This is the time how long the instant clip will be stored in the server memory + and can be accessed via public HLS/MP4 links. Download and/or use the instant + clip before this time expires. + + After the time has expired, the clip is deleted from memory and is no longer + available via the link. You need to create a new segment, or use + `vod_required: true` attribute. + + If value is omitted, then expiration is counted as +3600 seconds (1 hour) to the + end of the clip (i.e. `unix timestamp = + + 3600`). + + Allowed range: 1m <= expiration <= 4h. + + Example: + `24.05.2024 14:00:00 (GMT) + 60 seconds of duration + 3600 seconds of expiration = 24.05.2024 15:01:00 (GMT) is Unix timestamp = 1716562860` + + start: Starting point of the segment to cut. + + Unix timestamp in seconds, absolute value. Example: + `24.05.2024 14:00:00 (GMT) is Unix timestamp = 1716559200` + + If a value from the past is specified, it is used as the starting point for the + segment to cut. If the value is omitted, then clip will start from now. + + vod_required: Indicates if video needs to be stored also as permanent VOD + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/streaming/streams/{stream_id}/clip_recording", + body=maybe_transform( + { + "duration": duration, + "expiration": expiration, + "start": start, + "vod_required": vod_required, + }, + stream_create_clip_params.StreamCreateClipParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Clip, + ) + + def get( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Stream: + """ + Returns stream details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/streams/{stream_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Stream, + ) + + def list_clips( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StreamListClipsResponse: + """ + Get list of non expired instant clips for a stream. + + You can now use both MP4 just-in-time packager and HLS for all clips. Get URLs + from "hls_master" and "mp4_master". + + **How to download renditions of clips:** + + URLs contain "master" alias by default, which means maximum available quality + from ABR set (based on height metadata). There is also possibility to access + individual bitrates from ABR ladder. That works for both HLS and MP4. You can + replace manually "master" to a value from renditions list in order to get exact + bitrate/quality from the set. Example: + + - HLS 720p: + `https://CID.domain.com/rec/111_1000/rec_d7bsli54p8n4_qsid42_master.m3u8` + - HLS 720p: + `https://CID.domain.com/rec/111_1000/rec_d7bsli54p8n4_qsid42_media_1_360.m3u8` + - MP4 360p: + `https://CID.domain.com/rec/111_1000/rec_d7bsli54p8n4_qsid42_master.mp4` + - MP4 360p: + `https://CID.domain.com/rec/111_1000/rec_d7bsli54p8n4_qsid42_media_1_360.mp4` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/streams/{stream_id}/clip_recording", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=StreamListClipsResponse, + ) + + def start_recording( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StreamStartRecordingResponse: + """ + Start recording a stream. + + Stream will be recorded and automatically saved in our video hosting as a + separate video VOD: + + - ID of the stream from which the recording was organized is added to + "stream_id" field. You can find the video by that value later. + - Title of the video is based on pattern "Stream Record: {`stream_title`}, + {`recording_end_time_utc`}". + - Recording start time is stored in "recording_started_at" field. + - You can record the original stream or the transcoded one. Only the transcoded + version will contain overlays. Set the appropriate recording method when + creating the stream or before calling this recording method. Details in the + "record_type" parameter of the stream. + - If you have access to the premium feature of saving the original stream (so + not just transcoded renditions), then the link to the original file will be in + the "origin_url" field. Look at the description of the field how to use it. + + Stream must be live for the recording to start, please check fields "live" + and/or "backup_live". After the recording starts, field "recording" will switch + to "true", and the recording duration in seconds will appear in the + "recording_duration" field. + + Please, keep in mind that recording doesn't start instantly, it takes ±3-7 + seconds to initialize the process after executing this method. + + Stream recording stops when: + + - Explicit execution of the method /`stop_recording`. In this case, the file + will be completely saved and closed. When you execute the stream recording + method again, the recording will be made to a new video file. + - When sending the stream stops on the client side, or stops accidentally. In + this case, recording process is waiting for 10 seconds to resume recording: + + - If the stream resumes within that period, recording will continue to the same + file. + - After that period, the file will be completely saved and closed. + - If the stream suddenly resumes after this period, the recording will go to a + new file, because old file is closed already. Please, also note that if you + have long broadcasts, the recording will be cut into 4-hour videos. This value + is fixed, but can be changed upon request to the Support Team. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/streaming/streams/{stream_id}/start_recording", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=StreamStartRecordingResponse, + ) + + def stop_recording( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Stop recording a stream. + + Stream must be in "recording: true" state for recording to be stopped. + + If there was a recording, the created video entity will be returned. Otherwise + the response will be empty. Please see conditions and restrictions for recording + a stream in the description of method /`start_recording`. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._put( + f"/streaming/streams/{stream_id}/stop_recording", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + +class AsyncStreamsResource(AsyncAPIResource): + @cached_property + def overlays(self) -> AsyncOverlaysResource: + return AsyncOverlaysResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncStreamsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncStreamsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncStreamsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncStreamsResourceWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + active: bool | Omit = omit, + auto_record: bool | Omit = omit, + broadcast_ids: Iterable[int] | Omit = omit, + cdn_id: int | Omit = omit, + client_entity_data: str | Omit = omit, + client_user_id: int | Omit = omit, + dvr_duration: int | Omit = omit, + dvr_enabled: bool | Omit = omit, + hls_mpegts_endlist_tag: bool | Omit = omit, + html_overlay: bool | Omit = omit, + projection: Literal["regular", "vr360", "vr180", "vr360tb"] | Omit = omit, + pull: bool | Omit = omit, + quality_set_id: int | Omit = omit, + record_type: Literal["origin", "transcoded"] | Omit = omit, + uri: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Stream: + """ + Use this method to create a new live stream entity for broadcasting. + + The input in API may contain streams of different formats, including the most + common ones RTMP, RTMPS, SRT, HLS. Note that multicast MPEG-TS over UDP and + others are supported too, ask the Support Team please. + + For ingestion, you can use both PUSH and PULL methods. + + Also you can use the main and backup servers, which are geographically located + in different locations. By default, any free ingest points in the world are + used. Settings have been applied that deliver low-latency streams in the optimal + way. If for some reason you need to set a fixed ingest point, or if you need to + set the main and backup ingest points in the same region (for example, do not + send streams outside the EU or US), then contact our Support Team. + + The output is HLS and MPEG-DASH with ABR. We transcode video for you by our + cloud-based infrastructure. ABR ladder supports all qualities from SD to 8K HDR + 60fps. + + All our streams are Low Latency enabled. We support a delay of ±4 seconds for + video streams by utilizing Common Media Application Format (CMAF) technology. So + you obtain latency from the traditional 30-50 seconds to ±4 seconds only by + default. If you need legacy non-low-latency HLS, then look at HLS MPEG-TS + delivery below. + + You have access to additional functions such as: + + - DVR + - Recording + - Live clipping + - Restreaming + - (soon) AI Automatic Speech Recognition for subtitles/captions generating + + For more information see specific API methods, and the Knowledge Base. + + ![HTML Overlays](https://demo-files.gvideo.io/apidocs/low-latency-football.gif) + + Args: + name: Stream name. + + Often used as a human-readable name for the stream, but can contain any text you + wish. The values are not unique and may be repeated. + + Examples: + + - Conference in July + - Stream #10003 + - Open-Air Camera #31 Backstage + - 480fd499-2de2-4988-bc1a-a4eebe9818ee + + active: Stream switch between on and off. This is not an indicator of the status "stream + is receiving and it is LIVE", but rather an on/off switch. + + When stream is switched off, there is no way to process it: PULL is deactivated + and PUSH will return an error. + + - true – stream can be processed + - false – stream is off, and cannot be processed + + auto_record: Enables autotomatic recording of the stream when it started. So you don't need + to call recording manually. + + Result of recording is automatically added to video hosting. For details see the + /streams/`start_recording` method and in knowledge base + + Values: + + - true – auto recording is enabled + - false – auto recording is disabled + + broadcast_ids: IDs of broadcasts which will include this stream + + cdn_id: ID of custom CDN resource from which the content will be delivered (only if you + know what you do) + + client_entity_data: Custom meta field designed to store your own extra information about a video + entity: video source, video id, parameters, etc. We do not use this field in any + way when processing the stream. You can store any data in any format (string, + json, etc), saved as a text string. Example: + `client_entity_data = '{ "seq_id": "1234567890", "name": "John Doe", "iat": 1516239022 }'` + + client_user_id: Custom meta field for storing the Identifier in your system. We do not use this + field in any way when processing the stream. Example: `client_user_id = 1001` + + dvr_duration: DVR duration in seconds if DVR feature is enabled for the stream. So this is + duration of how far the user can rewind the live stream. + + `dvr_duration` range is [30...14400]. + + Maximum value is 4 hours = 14400 seconds. If you need more, ask the Support Team + please. + + dvr_enabled: + Enables DVR for the stream: + + - true – DVR is enabled + - false – DVR is disabled + + hls_mpegts_endlist_tag: Add `#EXT-X-ENDLIST` tag within .m3u8 playlist after the last segment of a live + stream when broadcast is ended. + + html_overlay: Switch on mode to insert and display real-time HTML overlay widgets on top of + live streams + + projection: Visualization mode for 360° streams, how the stream is rendered in our web + player ONLY. If you would like to show video 360° in an external video player, + then use parameters of that video player. + + Modes: + + - regular – regular “flat” stream + - vr360 – display stream in 360° mode + - vr180 – display stream in 180° mode + - vr360tb – display stream in 3D 360° mode Top-Bottom + + pull: Indicates if stream is pulled from external server or not. Has two possible + values: + + - true – stream is received by PULL method. Use this when need to get stream + from external server. + - false – stream is received by PUSH method. Use this when need to send stream + from end-device to our Streaming Platform, i.e. from your encoder, mobile app + or OBS Studio. + + quality_set_id: Custom quality set ID for transcoding, if transcoding is required according to + your conditions. Look at GET /`quality_sets` method + + record_type: Method of recording a stream. Specifies the source from which the stream will be + recorded: original or transcoded. + + Types: + + - "origin" – To record RMTP/SRT/etc original clean media source. + - "transcoded" – To record the output transcoded version of the stream, + including overlays, texts, logos, etc. additional media layers. + + uri: When using PULL method, this is the URL to pull a stream from. + + You can specify multiple addresses separated by a space (" "), so you can + organize a backup plan. In this case, the specified addresses will be selected + one by one using round robin scheduling. If the first address does not respond, + then the next one in the list will be automatically requested, returning to the + first and so on in a circle. Also, if the sucessfully working stream stops + sending data, then the next one will be selected according to the same scheme. + + After 2 hours of inactivity of your original stream, the system stops PULL + requests and the stream is deactivated (the "active" field switches to "false"). + + Please, note that this field is for PULL only, so is not suitable for PUSH. Look + at fields "push_url" and "push_url_srt" from GET method. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/streaming/streams", + body=await async_maybe_transform( + { + "name": name, + "active": active, + "auto_record": auto_record, + "broadcast_ids": broadcast_ids, + "cdn_id": cdn_id, + "client_entity_data": client_entity_data, + "client_user_id": client_user_id, + "dvr_duration": dvr_duration, + "dvr_enabled": dvr_enabled, + "hls_mpegts_endlist_tag": hls_mpegts_endlist_tag, + "html_overlay": html_overlay, + "projection": projection, + "pull": pull, + "quality_set_id": quality_set_id, + "record_type": record_type, + "uri": uri, + }, + stream_create_params.StreamCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Stream, + ) + + async def update( + self, + stream_id: int, + *, + stream: stream_update_params.Stream | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Stream: + """ + Updates stream settings + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/streaming/streams/{stream_id}", + body=await async_maybe_transform({"stream": stream}, stream_update_params.StreamUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Stream, + ) + + def list( + self, + *, + page: int | Omit = omit, + with_broadcasts: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Stream, AsyncPageStreaming[Stream]]: + """Returns a list of streams + + Args: + page: Query parameter. + + Use it to list the paginated content + + with_broadcasts: Query parameter. Set to 1 to get details of the broadcasts associated with the + stream + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/streams", + page=AsyncPageStreaming[Stream], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "page": page, + "with_broadcasts": with_broadcasts, + }, + stream_list_params.StreamListParams, + ), + ), + model=Stream, + ) + + async def delete( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a live stream. + + After deleting the live stream, all associated data is deleted: settings, PUSH + and PULL links, video playback links, etc. + + Live stream information is deleted permanently and irreversibly. Therefore, it + is impossible to restore data and files after this. + + But if the live had recordings, they continue to remain independent Video + entities. The "stream_id" parameter will simply point to a stream that no longer + exists. + + Perhaps, instead of deleting, you may use the stream deactivation: + + ``` + PATCH / videos / {stream_id} + {"active": false} + ``` + + For details, see the Product Documentation. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/streaming/streams/{stream_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def clear_dvr( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Clear live stream DVR + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._put( + f"/streaming/streams/{stream_id}/dvr_cleanup", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def create_clip( + self, + stream_id: int, + *, + duration: int, + expiration: int | Omit = omit, + start: int | Omit = omit, + vod_required: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Clip: + """ + Create an instant clip from on-going live stream. + + Instant clips are applicable in cases where there is no time to wait for the + broadcast to be completed and recorded. For example, for quickly cutting + highlights in sport events, or cutting an important moment in the news or live + performance. + + DVR function must be enabled for clip recording. If the DVR is disabled, the + response will be error 422. + + Instant clip becomes available for viewing in the following formats: + + - HLS .m3u8, + - MP4, + - VOD in video hosting with a permanent link to watch video. + + ![HTML Overlays](https://demo-files.gvideo.io/apidocs/clip_recording_mp4_hls.gif) + + **Clip lifetime:** + + Instant clips are a copy of the stream, created from a live stream. They are + stored in memory for a limited time, after which the clip ceases to exist and + you will receive a 404 on the link. + + Limits that you should keep in mind: + + - The clip's lifespan is controlled by `expiration` parameter. + - The default expiration value is 1 hour. The value can be set from 1 minute to + 4 hours. + - If you want a video for longer or permanent viewing, then create a regular VOD + based on the clip. This way you can use the clip's link for the first time, + and immediately after the transcoded version is ready, you can change by + yourself it to a permanent link of VOD. + - The clip becomes available only after it is completely copied from the live + stream. So the clip will be available after `start + duration` exact time. If + you try to request it before this time, the response will be error code 425 + "Too Early". + + **Cutting a clip from a source:** + + In order to use clips recording feature, DVR must be enabled for a stream: + "dvr_enabled: true". The DVR serves as a source for creating clips: + + - By default live stream DVR is set to 1 hour (3600 seconds). You can create an + instant clip using any segment of this time period by specifying the desired + start time and duration. + - If you create a clip, but the DVR expires, the clip will still exist for the + specified time as a copy of the stream. + + **Getting permanent VOD:** + + To get permanent VOD version of a live clip use this parameter when making a + request to create a clip: `vod_required: true`. + + Later, when the clip is ready, grab `video_id` value from the response and query + the video by regular GET /video/{id} method. + + Args: + duration: Requested segment duration in seconds to be cut. + + Please, note that cutting is based on the idea of instantly creating a clip, + instead of precise timing. So final segment may be: + + - Less than the specified value if there is less data in the DVR than the + requested segment. + - Greater than the specified value, because segment is aligned to the first and + last key frames of already stored fragment in DVR, this way -1 and +1 chunks + can be added to left and right. + + Duration of cutted segment cannot be greater than DVR duration for this stream. + Therefore, to change the maximum, use "dvr_duration" parameter of this stream. + + expiration: Expire time of the clip via a public link. + + Unix timestamp in seconds, absolute value. + + This is the time how long the instant clip will be stored in the server memory + and can be accessed via public HLS/MP4 links. Download and/or use the instant + clip before this time expires. + + After the time has expired, the clip is deleted from memory and is no longer + available via the link. You need to create a new segment, or use + `vod_required: true` attribute. + + If value is omitted, then expiration is counted as +3600 seconds (1 hour) to the + end of the clip (i.e. `unix timestamp = + + 3600`). + + Allowed range: 1m <= expiration <= 4h. + + Example: + `24.05.2024 14:00:00 (GMT) + 60 seconds of duration + 3600 seconds of expiration = 24.05.2024 15:01:00 (GMT) is Unix timestamp = 1716562860` + + start: Starting point of the segment to cut. + + Unix timestamp in seconds, absolute value. Example: + `24.05.2024 14:00:00 (GMT) is Unix timestamp = 1716559200` + + If a value from the past is specified, it is used as the starting point for the + segment to cut. If the value is omitted, then clip will start from now. + + vod_required: Indicates if video needs to be stored also as permanent VOD + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/streaming/streams/{stream_id}/clip_recording", + body=await async_maybe_transform( + { + "duration": duration, + "expiration": expiration, + "start": start, + "vod_required": vod_required, + }, + stream_create_clip_params.StreamCreateClipParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Clip, + ) + + async def get( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Stream: + """ + Returns stream details + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/streams/{stream_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Stream, + ) + + async def list_clips( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StreamListClipsResponse: + """ + Get list of non expired instant clips for a stream. + + You can now use both MP4 just-in-time packager and HLS for all clips. Get URLs + from "hls_master" and "mp4_master". + + **How to download renditions of clips:** + + URLs contain "master" alias by default, which means maximum available quality + from ABR set (based on height metadata). There is also possibility to access + individual bitrates from ABR ladder. That works for both HLS and MP4. You can + replace manually "master" to a value from renditions list in order to get exact + bitrate/quality from the set. Example: + + - HLS 720p: + `https://CID.domain.com/rec/111_1000/rec_d7bsli54p8n4_qsid42_master.m3u8` + - HLS 720p: + `https://CID.domain.com/rec/111_1000/rec_d7bsli54p8n4_qsid42_media_1_360.m3u8` + - MP4 360p: + `https://CID.domain.com/rec/111_1000/rec_d7bsli54p8n4_qsid42_master.mp4` + - MP4 360p: + `https://CID.domain.com/rec/111_1000/rec_d7bsli54p8n4_qsid42_media_1_360.mp4` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/streams/{stream_id}/clip_recording", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=StreamListClipsResponse, + ) + + async def start_recording( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StreamStartRecordingResponse: + """ + Start recording a stream. + + Stream will be recorded and automatically saved in our video hosting as a + separate video VOD: + + - ID of the stream from which the recording was organized is added to + "stream_id" field. You can find the video by that value later. + - Title of the video is based on pattern "Stream Record: {`stream_title`}, + {`recording_end_time_utc`}". + - Recording start time is stored in "recording_started_at" field. + - You can record the original stream or the transcoded one. Only the transcoded + version will contain overlays. Set the appropriate recording method when + creating the stream or before calling this recording method. Details in the + "record_type" parameter of the stream. + - If you have access to the premium feature of saving the original stream (so + not just transcoded renditions), then the link to the original file will be in + the "origin_url" field. Look at the description of the field how to use it. + + Stream must be live for the recording to start, please check fields "live" + and/or "backup_live". After the recording starts, field "recording" will switch + to "true", and the recording duration in seconds will appear in the + "recording_duration" field. + + Please, keep in mind that recording doesn't start instantly, it takes ±3-7 + seconds to initialize the process after executing this method. + + Stream recording stops when: + + - Explicit execution of the method /`stop_recording`. In this case, the file + will be completely saved and closed. When you execute the stream recording + method again, the recording will be made to a new video file. + - When sending the stream stops on the client side, or stops accidentally. In + this case, recording process is waiting for 10 seconds to resume recording: + + - If the stream resumes within that period, recording will continue to the same + file. + - After that period, the file will be completely saved and closed. + - If the stream suddenly resumes after this period, the recording will go to a + new file, because old file is closed already. Please, also note that if you + have long broadcasts, the recording will be cut into 4-hour videos. This value + is fixed, but can be changed upon request to the Support Team. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/streaming/streams/{stream_id}/start_recording", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=StreamStartRecordingResponse, + ) + + async def stop_recording( + self, + stream_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Stop recording a stream. + + Stream must be in "recording: true" state for recording to be stopped. + + If there was a recording, the created video entity will be returned. Otherwise + the response will be empty. Please see conditions and restrictions for recording + a stream in the description of method /`start_recording`. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._put( + f"/streaming/streams/{stream_id}/stop_recording", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + +class StreamsResourceWithRawResponse: + def __init__(self, streams: StreamsResource) -> None: + self._streams = streams + + self.create = to_raw_response_wrapper( + streams.create, + ) + self.update = to_raw_response_wrapper( + streams.update, + ) + self.list = to_raw_response_wrapper( + streams.list, + ) + self.delete = to_raw_response_wrapper( + streams.delete, + ) + self.clear_dvr = to_raw_response_wrapper( + streams.clear_dvr, + ) + self.create_clip = to_raw_response_wrapper( + streams.create_clip, + ) + self.get = to_raw_response_wrapper( + streams.get, + ) + self.list_clips = to_raw_response_wrapper( + streams.list_clips, + ) + self.start_recording = to_raw_response_wrapper( + streams.start_recording, + ) + self.stop_recording = to_raw_response_wrapper( + streams.stop_recording, + ) + + @cached_property + def overlays(self) -> OverlaysResourceWithRawResponse: + return OverlaysResourceWithRawResponse(self._streams.overlays) + + +class AsyncStreamsResourceWithRawResponse: + def __init__(self, streams: AsyncStreamsResource) -> None: + self._streams = streams + + self.create = async_to_raw_response_wrapper( + streams.create, + ) + self.update = async_to_raw_response_wrapper( + streams.update, + ) + self.list = async_to_raw_response_wrapper( + streams.list, + ) + self.delete = async_to_raw_response_wrapper( + streams.delete, + ) + self.clear_dvr = async_to_raw_response_wrapper( + streams.clear_dvr, + ) + self.create_clip = async_to_raw_response_wrapper( + streams.create_clip, + ) + self.get = async_to_raw_response_wrapper( + streams.get, + ) + self.list_clips = async_to_raw_response_wrapper( + streams.list_clips, + ) + self.start_recording = async_to_raw_response_wrapper( + streams.start_recording, + ) + self.stop_recording = async_to_raw_response_wrapper( + streams.stop_recording, + ) + + @cached_property + def overlays(self) -> AsyncOverlaysResourceWithRawResponse: + return AsyncOverlaysResourceWithRawResponse(self._streams.overlays) + + +class StreamsResourceWithStreamingResponse: + def __init__(self, streams: StreamsResource) -> None: + self._streams = streams + + self.create = to_streamed_response_wrapper( + streams.create, + ) + self.update = to_streamed_response_wrapper( + streams.update, + ) + self.list = to_streamed_response_wrapper( + streams.list, + ) + self.delete = to_streamed_response_wrapper( + streams.delete, + ) + self.clear_dvr = to_streamed_response_wrapper( + streams.clear_dvr, + ) + self.create_clip = to_streamed_response_wrapper( + streams.create_clip, + ) + self.get = to_streamed_response_wrapper( + streams.get, + ) + self.list_clips = to_streamed_response_wrapper( + streams.list_clips, + ) + self.start_recording = to_streamed_response_wrapper( + streams.start_recording, + ) + self.stop_recording = to_streamed_response_wrapper( + streams.stop_recording, + ) + + @cached_property + def overlays(self) -> OverlaysResourceWithStreamingResponse: + return OverlaysResourceWithStreamingResponse(self._streams.overlays) + + +class AsyncStreamsResourceWithStreamingResponse: + def __init__(self, streams: AsyncStreamsResource) -> None: + self._streams = streams + + self.create = async_to_streamed_response_wrapper( + streams.create, + ) + self.update = async_to_streamed_response_wrapper( + streams.update, + ) + self.list = async_to_streamed_response_wrapper( + streams.list, + ) + self.delete = async_to_streamed_response_wrapper( + streams.delete, + ) + self.clear_dvr = async_to_streamed_response_wrapper( + streams.clear_dvr, + ) + self.create_clip = async_to_streamed_response_wrapper( + streams.create_clip, + ) + self.get = async_to_streamed_response_wrapper( + streams.get, + ) + self.list_clips = async_to_streamed_response_wrapper( + streams.list_clips, + ) + self.start_recording = async_to_streamed_response_wrapper( + streams.start_recording, + ) + self.stop_recording = async_to_streamed_response_wrapper( + streams.stop_recording, + ) + + @cached_property + def overlays(self) -> AsyncOverlaysResourceWithStreamingResponse: + return AsyncOverlaysResourceWithStreamingResponse(self._streams.overlays) diff --git a/src/gcore/resources/streaming/videos/__init__.py b/src/gcore/resources/streaming/videos/__init__.py new file mode 100644 index 00000000..78c3959d --- /dev/null +++ b/src/gcore/resources/streaming/videos/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .videos import ( + VideosResource, + AsyncVideosResource, + VideosResourceWithRawResponse, + AsyncVideosResourceWithRawResponse, + VideosResourceWithStreamingResponse, + AsyncVideosResourceWithStreamingResponse, +) +from .subtitles import ( + SubtitlesResource, + AsyncSubtitlesResource, + SubtitlesResourceWithRawResponse, + AsyncSubtitlesResourceWithRawResponse, + SubtitlesResourceWithStreamingResponse, + AsyncSubtitlesResourceWithStreamingResponse, +) + +__all__ = [ + "SubtitlesResource", + "AsyncSubtitlesResource", + "SubtitlesResourceWithRawResponse", + "AsyncSubtitlesResourceWithRawResponse", + "SubtitlesResourceWithStreamingResponse", + "AsyncSubtitlesResourceWithStreamingResponse", + "VideosResource", + "AsyncVideosResource", + "VideosResourceWithRawResponse", + "AsyncVideosResourceWithRawResponse", + "VideosResourceWithStreamingResponse", + "AsyncVideosResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/streaming/videos/subtitles.py b/src/gcore/resources/streaming/videos/subtitles.py new file mode 100644 index 00000000..c483d4b5 --- /dev/null +++ b/src/gcore/resources/streaming/videos/subtitles.py @@ -0,0 +1,661 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.streaming.videos import subtitle_create_params, subtitle_update_params +from ....types.streaming.subtitle import Subtitle +from ....types.streaming.subtitle_base import SubtitleBase +from ....types.streaming.videos.subtitle_list_response import SubtitleListResponse + +__all__ = ["SubtitlesResource", "AsyncSubtitlesResource"] + + +class SubtitlesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SubtitlesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return SubtitlesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SubtitlesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return SubtitlesResourceWithStreamingResponse(self) + + def create( + self, + video_id: int, + *, + body: subtitle_create_params.Body, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Subtitle: + """ + Add new subtitle/captions to a video entity. + + **Add already exist subtitles** + + Subtitles must be in one of the following formats: + + - SRT – SubRip Text is described on + [wikipedia.org](https://en.wikipedia.org/wiki/SubRip#SubRip_file_format). Must + start from integer for sequence number. Use calidators to check the subtitles, + like + [srt-validator](https://taoning2014.github.io/srt-validator-website/index.html). + - WebVTT – Web Video Text Tracks Format is described on + [developer.mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/WebVTT_API). + Must start from "WEBVTT" header. Use validators to check the subtitles, like + [W3C](https://w3c.github.io/webvtt.js/parser.html). + + Language is 3-letter language code according to ISO-639-2 (bibliographic code). + Specify language you need, or just look at our list in the attribute + "audio_language" of section + ["AI Speech Recognition"](/docs/api-reference/streaming/ai/create-ai-asr-task). + + You can add multiple subtitles in the same language, language uniqueness is not + required. + + Size must be up to 5Mb. + + The update time for added or changed subtitles is up to 30 seconds. Just like + videos, subtitles are cached, so it takes time to update the data. + + **AI subtitles and transcribing** + + It is also possible to automatically create subtitles based on AI. + + Read more: + + - What is + ["AI Speech Recognition"](/docs/api-reference/streaming/ai/create-ai-asr-task). + - If the option is enabled via + `auto_transcribe_audio_language: auto|`, then immediately after + successful transcoding, an AI task will be automatically created for + transcription. + - If you need to translate subtitles from original language to any other, then + AI-task of subtitles translation can be applied. Use + `auto_translate_subtitles_language: default|` parameter for + that. Also you can point several languages to translate to, then a separate + subtitle will be generated for each specified language. The created AI-task(s) + will be automatically executed, and result will also be automatically attached + to this video as subtitle(s). + + If AI is disabled in your account, you will receive code 422 in response. + + **Where and how subtitles are displayed?** + + Subtitles are became available in the API response and in playback manifests. + + All added subtitles are automatically inserted into the output manifest .m3u8. + This way, subtitles become available to any player: our player, OS built-in, or + other specialized ones. You don't need to do anything else. Read more + information in the Knowledge Base. + + Example: + + ``` + # EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs0",NAME="English",LANGUAGE="en",AUTOSELECT=YES,URI="subs-0.m3u8" + ``` + + ![Auto generated subtitles example](https://demo-files.gvideo.io/apidocs/captions.gif) + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/streaming/videos/{video_id}/subtitles", + body=maybe_transform(body, subtitle_create_params.SubtitleCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Subtitle, + ) + + def update( + self, + id: int, + *, + video_id: int, + language: str | Omit = omit, + name: str | Omit = omit, + vtt: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SubtitleBase: + """ + Method to update subtitle of a video. + + You can update all or only some of fields you need. + + If you want to replace the text of subtitles (i.e. found a typo in the text, or + the timing in the video changed), then: + + - download it using GET method, + - change it in an external editor, + - and update it using this PATCH method. + + Just like videos, subtitles are cached, so it takes time to update the data. See + POST method for details. + + Args: + language: 3-letter language code according to ISO-639-2 (bibliographic code) + + name: Name of subtitle file + + vtt: Full text of subtitles/captions, with escaped "\n" ("\r") symbol of new line + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/streaming/videos/{video_id}/subtitles/{id}", + body=maybe_transform( + { + "language": language, + "name": name, + "vtt": vtt, + }, + subtitle_update_params.SubtitleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SubtitleBase, + ) + + def list( + self, + video_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SubtitleListResponse: + """ + Method returns a list of all subtitles that are already attached to a video. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/videos/{video_id}/subtitles", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SubtitleListResponse, + ) + + def delete( + self, + id: int, + *, + video_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete specified video subtitle + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/streaming/videos/{video_id}/subtitles/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + id: int, + *, + video_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Subtitle: + """ + Returns information about a specific subtitle for a video. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/videos/{video_id}/subtitles/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Subtitle, + ) + + +class AsyncSubtitlesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSubtitlesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncSubtitlesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSubtitlesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncSubtitlesResourceWithStreamingResponse(self) + + async def create( + self, + video_id: int, + *, + body: subtitle_create_params.Body, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Subtitle: + """ + Add new subtitle/captions to a video entity. + + **Add already exist subtitles** + + Subtitles must be in one of the following formats: + + - SRT – SubRip Text is described on + [wikipedia.org](https://en.wikipedia.org/wiki/SubRip#SubRip_file_format). Must + start from integer for sequence number. Use calidators to check the subtitles, + like + [srt-validator](https://taoning2014.github.io/srt-validator-website/index.html). + - WebVTT – Web Video Text Tracks Format is described on + [developer.mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/WebVTT_API). + Must start from "WEBVTT" header. Use validators to check the subtitles, like + [W3C](https://w3c.github.io/webvtt.js/parser.html). + + Language is 3-letter language code according to ISO-639-2 (bibliographic code). + Specify language you need, or just look at our list in the attribute + "audio_language" of section + ["AI Speech Recognition"](/docs/api-reference/streaming/ai/create-ai-asr-task). + + You can add multiple subtitles in the same language, language uniqueness is not + required. + + Size must be up to 5Mb. + + The update time for added or changed subtitles is up to 30 seconds. Just like + videos, subtitles are cached, so it takes time to update the data. + + **AI subtitles and transcribing** + + It is also possible to automatically create subtitles based on AI. + + Read more: + + - What is + ["AI Speech Recognition"](/docs/api-reference/streaming/ai/create-ai-asr-task). + - If the option is enabled via + `auto_transcribe_audio_language: auto|`, then immediately after + successful transcoding, an AI task will be automatically created for + transcription. + - If you need to translate subtitles from original language to any other, then + AI-task of subtitles translation can be applied. Use + `auto_translate_subtitles_language: default|` parameter for + that. Also you can point several languages to translate to, then a separate + subtitle will be generated for each specified language. The created AI-task(s) + will be automatically executed, and result will also be automatically attached + to this video as subtitle(s). + + If AI is disabled in your account, you will receive code 422 in response. + + **Where and how subtitles are displayed?** + + Subtitles are became available in the API response and in playback manifests. + + All added subtitles are automatically inserted into the output manifest .m3u8. + This way, subtitles become available to any player: our player, OS built-in, or + other specialized ones. You don't need to do anything else. Read more + information in the Knowledge Base. + + Example: + + ``` + # EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs0",NAME="English",LANGUAGE="en",AUTOSELECT=YES,URI="subs-0.m3u8" + ``` + + ![Auto generated subtitles example](https://demo-files.gvideo.io/apidocs/captions.gif) + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/streaming/videos/{video_id}/subtitles", + body=await async_maybe_transform(body, subtitle_create_params.SubtitleCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Subtitle, + ) + + async def update( + self, + id: int, + *, + video_id: int, + language: str | Omit = omit, + name: str | Omit = omit, + vtt: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SubtitleBase: + """ + Method to update subtitle of a video. + + You can update all or only some of fields you need. + + If you want to replace the text of subtitles (i.e. found a typo in the text, or + the timing in the video changed), then: + + - download it using GET method, + - change it in an external editor, + - and update it using this PATCH method. + + Just like videos, subtitles are cached, so it takes time to update the data. See + POST method for details. + + Args: + language: 3-letter language code according to ISO-639-2 (bibliographic code) + + name: Name of subtitle file + + vtt: Full text of subtitles/captions, with escaped "\n" ("\r") symbol of new line + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/streaming/videos/{video_id}/subtitles/{id}", + body=await async_maybe_transform( + { + "language": language, + "name": name, + "vtt": vtt, + }, + subtitle_update_params.SubtitleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SubtitleBase, + ) + + async def list( + self, + video_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SubtitleListResponse: + """ + Method returns a list of all subtitles that are already attached to a video. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/videos/{video_id}/subtitles", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SubtitleListResponse, + ) + + async def delete( + self, + id: int, + *, + video_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete specified video subtitle + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/streaming/videos/{video_id}/subtitles/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + id: int, + *, + video_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Subtitle: + """ + Returns information about a specific subtitle for a video. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/videos/{video_id}/subtitles/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Subtitle, + ) + + +class SubtitlesResourceWithRawResponse: + def __init__(self, subtitles: SubtitlesResource) -> None: + self._subtitles = subtitles + + self.create = to_raw_response_wrapper( + subtitles.create, + ) + self.update = to_raw_response_wrapper( + subtitles.update, + ) + self.list = to_raw_response_wrapper( + subtitles.list, + ) + self.delete = to_raw_response_wrapper( + subtitles.delete, + ) + self.get = to_raw_response_wrapper( + subtitles.get, + ) + + +class AsyncSubtitlesResourceWithRawResponse: + def __init__(self, subtitles: AsyncSubtitlesResource) -> None: + self._subtitles = subtitles + + self.create = async_to_raw_response_wrapper( + subtitles.create, + ) + self.update = async_to_raw_response_wrapper( + subtitles.update, + ) + self.list = async_to_raw_response_wrapper( + subtitles.list, + ) + self.delete = async_to_raw_response_wrapper( + subtitles.delete, + ) + self.get = async_to_raw_response_wrapper( + subtitles.get, + ) + + +class SubtitlesResourceWithStreamingResponse: + def __init__(self, subtitles: SubtitlesResource) -> None: + self._subtitles = subtitles + + self.create = to_streamed_response_wrapper( + subtitles.create, + ) + self.update = to_streamed_response_wrapper( + subtitles.update, + ) + self.list = to_streamed_response_wrapper( + subtitles.list, + ) + self.delete = to_streamed_response_wrapper( + subtitles.delete, + ) + self.get = to_streamed_response_wrapper( + subtitles.get, + ) + + +class AsyncSubtitlesResourceWithStreamingResponse: + def __init__(self, subtitles: AsyncSubtitlesResource) -> None: + self._subtitles = subtitles + + self.create = async_to_streamed_response_wrapper( + subtitles.create, + ) + self.update = async_to_streamed_response_wrapper( + subtitles.update, + ) + self.list = async_to_streamed_response_wrapper( + subtitles.list, + ) + self.delete = async_to_streamed_response_wrapper( + subtitles.delete, + ) + self.get = async_to_streamed_response_wrapper( + subtitles.get, + ) diff --git a/src/gcore/resources/streaming/videos/videos.py b/src/gcore/resources/streaming/videos/videos.py new file mode 100644 index 00000000..60c435c3 --- /dev/null +++ b/src/gcore/resources/streaming/videos/videos.py @@ -0,0 +1,1677 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from .subtitles import ( + SubtitlesResource, + AsyncSubtitlesResource, + SubtitlesResourceWithRawResponse, + AsyncSubtitlesResourceWithRawResponse, + SubtitlesResourceWithStreamingResponse, + AsyncSubtitlesResourceWithStreamingResponse, +) +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncPageStreaming, AsyncPageStreaming +from ...._base_client import AsyncPaginator, make_request_options +from ....types.streaming import ( + video_list_params, + video_create_params, + video_update_params, + video_list_names_params, + video_create_multiple_params, +) +from ....types.streaming.video import Video +from ....types.streaming.create_video_param import CreateVideoParam +from ....types.streaming.video_create_response import VideoCreateResponse +from ....types.streaming.direct_upload_parameters import DirectUploadParameters +from ....types.streaming.video_create_multiple_response import VideoCreateMultipleResponse + +__all__ = ["VideosResource", "AsyncVideosResource"] + + +class VideosResource(SyncAPIResource): + @cached_property + def subtitles(self) -> SubtitlesResource: + return SubtitlesResource(self._client) + + @cached_property + def with_raw_response(self) -> VideosResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return VideosResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> VideosResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return VideosResourceWithStreamingResponse(self) + + def create( + self, + *, + video: CreateVideoParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VideoCreateResponse: + """ + Use this method to create a new video entity. + + **Methods of creating** + + To upload the original video file to the server, there are several possible + scenarios: + + - **Copy from another server** – If your video is accessable via "http://", + "https://", or "sftp://" public link, then you can use this method to copy a + file from an external server. Set `origin_url` parameter with the link to the + original video file (i.e. "https://domain.com/video.mp4"). After method + execution file will be uploaded and will be sent to transcoding automatically, + you don't have to do anything else. Use extra field `origin_http_headers` if + authorization is required on the external server. + - **Direct upload from a local device** – If you need to upload video directly + from your local device or from a mobile app, then use this method. Keep + `origin_url` empty and use TUS protocol ([tus.io](https://tus.io)) to upload + file. More details are here + ["Get TUS' upload"](/docs/api-reference/streaming/videos/get-tus-parameters-for-direct-upload) + + After getting the video, it is processed through the queue. There are 2 priority + criteria: global and local. Global is determined automatically by the system as + converters are ready to get next video, so your videos rarely queue longer than + usual (when you don't have a dedicated region). Local priority works at the + level of your account and you have full control over it, look at "priority" + attribute. + + **AI processing** + + When uploading a video, it is possible to automatically create subtitles based + on AI. + + Read more: + + - What is + ["AI Speech Recognition"](/docs/api-reference/streaming/ai/create-ai-asr-task). + - If the option is enabled via + `auto_transcribe_audio_language: auto|`, then immediately after + successful transcoding, an AI task will be automatically created for + transcription. + - If you need to translate subtitles from original language to any other, then + AI-task of subtitles translation can be applied. Use + `auto_translate_subtitles_language: default|` parameter for + that. Also you can point several languages to translate to, then a separate + subtitle will be generated for each specified language. + - How to + ["add AI-generated subtitles to an exist video"](/docs/api-reference/streaming/subtitles/add-subtitle). + + The created AI-task(s) will be automatically executed, and result will also be + automatically attached to this video as subtitle(s). + + Please note that transcription is done automatically for all videos uploaded to + our video hosting. If necessary, you can disable automatic creation of + subtitles. If AI is disabled in your account, no AI functionality is called. + + **Advanced Features** For details on the requirements for incoming original + files, and output video parameters after transcoding, refer to the Knowledge + Base documentation. By default video will be transcoded according to the + original resolution, and a quality ladder suitable for your original video will + be applied. There is no automatic upscaling; the maximum quality is taken from + the original video. If you want to upload specific files not explicitly listed + in requirements or wish to modify the standard quality ladder (i.e. decrease + quality or add new non-standard qualities), then such customization is possible. + Please reach out to us for assistance. + + Additionally, check the Knowledge Base for any supplementary information you may + need. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/streaming/videos", + body=maybe_transform({"video": video}, video_create_params.VideoCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VideoCreateResponse, + ) + + def update( + self, + video_id: int, + *, + name: str, + auto_transcribe_audio_language: Literal["disable", "auto", ""] | Omit = omit, + auto_translate_subtitles_language: Literal["disable", "default", ""] | Omit = omit, + client_user_id: int | Omit = omit, + clip_duration_seconds: int | Omit = omit, + clip_start_seconds: int | Omit = omit, + custom_iframe_url: str | Omit = omit, + description: str | Omit = omit, + directory_id: int | Omit = omit, + origin_http_headers: str | Omit = omit, + origin_url: str | Omit = omit, + poster: str | Omit = omit, + priority: int | Omit = omit, + projection: str | Omit = omit, + quality_set_id: int | Omit = omit, + remote_poster_url: str | Omit = omit, + remove_poster: bool | Omit = omit, + screenshot_id: int | Omit = omit, + share_url: str | Omit = omit, + source_bitrate_limit: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Changes parameters of the video to new values. + + It's allowed to update only those public parameters that are described in POST + method to create a new “video” entity. So it's not possible to change calculated + parameters like "id", "duration", "hls_url", etc. + + Examples of changing: + + - Name: `{ "name": "new name of the video" }` + - Move the video to a new directory: ` { "directory_id": 200 }` + + Please note that some parameters are used on initial step (before transcoding) + only, so after transcoding there is no use in changing their values. For + example, "origin_url" parameter is used for downloading an original file from a + source and never used after transcoding; or "priority" parameter is used to set + priority of processing and never used after transcoding. + + Args: + name: Video name + + auto_transcribe_audio_language: Automatic creation of subtitles by transcribing the audio track. + + Values: + + - disable – Do not transcribe. + - auto – Automatically detects the activation of the option based on the + settings in your account. If generation is activated, then automatic language + detection while transcribing. + - \\ – Transcribe from specific language. Can be used to specify the exact + language spoken in the audio track, or when auto language detection fails. + Language is set by 3-letter language code according to ISO-639-2 + (bibliographic code). List of languages is available in `audio_language` + attribute of API POST /streaming/ai/transcribe . + + Example: + + ``` + auto_transcribe_audio_language: "auto" + auto_transcribe_audio_language: "ger" + ``` + + More details: + + - List of AI tasks – API + [GET /streaming/ai/tasks](/docs/api-reference/streaming/ai/get-list-of-ai-tasks) + - Add subtitles to an exist video – API + [POST /streaming/videos/{`video_id`}/subtitles](/docs/api-reference/streaming/subtitles/add-subtitle). + + auto_translate_subtitles_language: Automatic translation of auto-transcribed subtitles to the specified + language(s). Can be used both together with `auto_transcribe_audio_language` + option only. + + Use it when you want to make automatic subtitles in languages other than the + original language in audio. + + Values: + + - disable – Do not translate. + - default – There are 3 default languages: eng,fre,ger + - \\ – Explicit language to translate to, or list of languages separated by a + comma. Look at list of available languages in description of AI ASR task + creation. + + If several languages are specified for translation, a separate subtitle will be + generated for each language. + + Example: + + ``` + auto_translate_subtitles_language: default + auto_translate_subtitles_language: eng,fre,ger + ``` + + Please note that subtitle translation is done separately and after + transcription. Thus separate AI-tasks are created for translation. + + client_user_id: Custom field where you can specify user ID in your system + + clip_duration_seconds: The length of the trimmed segment to transcode, instead of the entire length of + the video. Is only used in conjunction with specifying the start of a segment. + Transcoding duration is a number in seconds. + + clip_start_seconds: If you want to transcode only a trimmed segment of a video instead of entire + length if the video, then you can provide timecodes of starting point and + duration of a segment to process. Start encoding from is a number in seconds. + + custom_iframe_url: Deprecated. + + Custom URL of IFrame for video player to be used in share panel in player. Auto + generated IFrame URL provided by default + + description: Video details; not visible to the end-users + + directory_id: ID of the directory where the video should be uploaded. (beta) + + origin_http_headers: Authorization HTTP request header. Will be used as credentials to authenticate a + request to download a file (specified in "origin_url" parameter) on an external + server. + + Syntax: `Authorization: ` + + Examples: + + - "origin_http_headers": "Authorization: Basic ..." + - "origin_http_headers": "Authorization: Bearer ..." + - "origin_http_headers": "Authorization: APIKey ..." Example of usage when + downloading a file from Google Drive: + + ``` + POST https://api.gcore.com/streaming/videos + + "video": { + "name": "IBC 2024 intro.mp4", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "origin_http_headers": "Authorization: Bearer ABC" + } + ``` + + origin_url: URL to an original file which you want to copy from external storage. If + specified, system will download the file and will use it as video source for + transcoding. + + poster: Poster is your own static image which can be displayed before the video starts. + + After uploading the video, the system will automatically create several + screenshots (they will be stored in "screenshots" attribute) from which you can + select an default screenshot. This "poster" field is for uploading your own + image. Also use attribute "screenshot_id" to select poster as a default + screnshot. + + Attribute accepts single image as base64-encoded string + [(RFC 2397 – The "data" URL scheme)](https://www.rfc-editor.org/rfc/rfc2397). In + format: `data:[];base64,` + + MIME-types are image/jpeg, image/webp, and image/png and file sizes up to 1Mb. + + Examples: + + - `data:image/jpeg;base64,/9j/4AA...qf/2Q==` + - `data:image/png;base64,iVBORw0KGg...ggg==` + - `data:image/webp;base64,UklGRt.../DgAAAAA` + + priority: Priority allows you to adjust the urgency of processing some videos before + others in your account, if your algorithm requires it. For example, when there + are very urgent video and some regular ones that can wait in the queue. + + Value range, integer [-10..10]. -10 is the lowest down-priority, 10 is the + highest up-priority. Default priority is 0. + + projection: Deprecated. + + Regulates the video format: + + - **regular** — plays the video as usual + - **vr360** — plays the video in 360 degree mode + - **vr180** — plays the video in 180 degree mode + - **vr360tb** — plays the video in 3D 360 degree mode Top-Bottom. + + Default is regular + + quality_set_id: Custom quality set ID for transcoding, if transcoding is required according to + your conditions. Look at GET /`quality_sets` method + + remote_poster_url: Poster URL to download from external resource, instead of uploading via "poster" + attribute. + + It has the same restrictions as "poster" attribute. + + remove_poster: Set it to true to remove poster + + screenshot_id: Default screenshot index. + + Specify an ID from the "screenshots" array, so that the URL of the required + screenshot appears in the "screenshot" attribute as the default screenshot. By + default 5 static screenshots will be taken from different places in the video + after transcoding. If the video is short, there may be fewer screenshots. + + Counting from 0. A value of -1 sets the default screenshot to the URL of your + own image from the "poster" attribute. + + Look at "screenshot" attribute in GET /videos/{`video_id`} for details. + + share_url: Deprecated. + + Custom URL or iframe displayed in the link field when a user clicks on a sharing + button in player. If empty, the link field and social network sharing is + disabled + + source_bitrate_limit: The option allows you to set the video transcoding rule so that the output + bitrate in ABR ladder is not exceeding the bitrate of the original video. + + This option is for advanced users only. + + By default `source_bitrate_limit: true` this option allows you to have the + output bitrate not more than in the original video, thus to transcode video + faster and to deliver it to end-viewers faster as well. At the same time, the + quality will be similar to the original. + + If for some reason you need more byte-space in the output quality when encoding, + you can set this option to `source_bitrate_limit: false`. Then, when + transcoding, the quality ceiling will be raised from the bitrate of the original + video to the maximum possible limit specified in our the Product Documentation. + For example, this may be needed when: + + - to improve the visual quality parameters using PSNR, SSIM, VMAF metrics, + - to improve the picture quality on dynamic scenes, + - etc. + + The option is applied only at the video creation stage and cannot be changed + later. If you want to re-transcode the video using new value, then you need to + create and upload a new video only. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/streaming/videos/{video_id}", + body=maybe_transform( + { + "name": name, + "auto_transcribe_audio_language": auto_transcribe_audio_language, + "auto_translate_subtitles_language": auto_translate_subtitles_language, + "client_user_id": client_user_id, + "clip_duration_seconds": clip_duration_seconds, + "clip_start_seconds": clip_start_seconds, + "custom_iframe_url": custom_iframe_url, + "description": description, + "directory_id": directory_id, + "origin_http_headers": origin_http_headers, + "origin_url": origin_url, + "poster": poster, + "priority": priority, + "projection": projection, + "quality_set_id": quality_set_id, + "remote_poster_url": remote_poster_url, + "remove_poster": remove_poster, + "screenshot_id": screenshot_id, + "share_url": share_url, + "source_bitrate_limit": source_bitrate_limit, + }, + video_update_params.VideoUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + def list( + self, + *, + id: str | Omit = omit, + client_user_id: int | Omit = omit, + fields: str | Omit = omit, + page: int | Omit = omit, + per_page: int | Omit = omit, + search: str | Omit = omit, + status: str | Omit = omit, + stream_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncPageStreaming[Video]: + """ + Returns a set of videos by the given criteria. + + Args: + id: IDs of the videos to find. You can specify one or more identifiers separated by + commas. Example, ?id=1,101,1001 + + client_user_id: Find videos where "client_user_id" meta field is equal to the search value + + fields: Restriction to return only the specified attributes, instead of the entire + dataset. Specify, if you need to get short response. The following fields are + available for specifying: id, name, duration, status, `created_at`, + `updated_at`, `hls_url`, screenshots, `converted_videos`, priority, `stream_id`. + Example, ?fields=id,name,`hls_url` + + page: Page number. Use it to list the paginated content + + per_page: Items per page number. Use it to list the paginated content + + search: Aggregated search condition. If set, the video list is filtered by one combined + SQL criterion: + + - id={s} OR slug={s} OR name like {s} + + i.e. "/videos?search=1000" returns list of videos where id=1000 or slug=1000 or + name contains "1000". + + status: + Use it to get videos filtered by their status. Possible values: + + - empty + - pending + - viewable + - ready + - error + + stream_id: Find videos recorded from a specific stream, so for which "stream_id" field is + equal to the search value + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/videos", + page=SyncPageStreaming[Video], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "id": id, + "client_user_id": client_user_id, + "fields": fields, + "page": page, + "per_page": per_page, + "search": search, + "status": status, + "stream_id": stream_id, + }, + video_list_params.VideoListParams, + ), + ), + model=Video, + ) + + def delete( + self, + video_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Operation to delete video entity. + + When you delete a video, all transcoded qualities and all associated files such + as subtitles and screenshots, as well as other data, are deleted from cloud + storage. + + The video is deleted permanently and irreversibly. Therefore, it is impossible + to restore files after this. + + For detailed information and information on calculating your maximum monthly + storage usage, please refer to the Product Documentation. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/streaming/videos/{video_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def create_multiple( + self, + *, + fields: str | Omit = omit, + videos: Iterable[video_create_multiple_params.Video] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VideoCreateMultipleResponse: + """Mass upload of your videos. + + Method is used to set the task of creating videos in + the form of 1 aggregated request instead of a large number of single requests. + + An additional advantage is the ability to specify subtitles in the same request. + Whereas for a normal single upload, subtitles are uploaded in separate requests. + + All videos in the request will be processed in queue in order of priority. Use + "priority" attribute and look at general description in POST /videos method. + + Limits: + + - Batch max size = 500 videos. + - Max body size (payload) = 64MB. + - API connection timeout = 30 sec. + + Args: + fields: Restriction to return only the specified attributes, instead of the entire + dataset. Specify, if you need to get short response. The following fields are + available for specifying: id, name, duration, status, `created_at`, + `updated_at`, `hls_url`, screenshots, `converted_videos`, priority. Example, + ?fields=id,name,`hls_url` + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/streaming/videos/batch", + body=maybe_transform({"videos": videos}, video_create_multiple_params.VideoCreateMultipleParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"fields": fields}, video_create_multiple_params.VideoCreateMultipleParams), + ), + cast_to=VideoCreateMultipleResponse, + ) + + def get( + self, + video_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Information about a video entity. + + Contains all the data about the video: meta-data, data for streaming and + renditions, static media data, data about original video. + + You can use different methods to play video: + + - `iframe_url` – a URL to a built-in HTML video player with automatically + configured video playback. + - `hls_url` – a URLs to HLS TS .m3u8 manifest, which can be played in video + players. + - `hls_cmaf_url` – a URL to HLS CMAF .m3u8 manifest with chunks in fMP4 format, + which can be played in most modern video players. + - `dash_url` – a URL to MPEG-DASH .mpd manifest, which can be played in most + modern video players. Preferable for Android and Windows devices. + - `converted_videos`/`mp4_url` – a URL to MP4 file of specific rendition. + + ![Video player](https://demo-files.gvideo.io/apidocs/coffee-run-player.jpg) + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/videos/{video_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + def get_parameters_for_direct_upload( + self, + video_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DirectUploadParameters: + """ + Use this method to get TUS' session parameters: hostname of the server to + upload, secure token. + + The general sequence of actions for a direct upload of a video is as follows: + + - Create video entity via POST method + ["Create video"](/docs/api-reference/streaming/videos/create-video) + - Get TUS' session parameters (you are here now) + - Upload file via TUS client, choose your implementation on + [tus.io](https://tus.io/implementations) + + Final endpoint for uploading is constructed using the following template: + "https://{hostname}/upload/". Also you have to provide token, `client_id`, + `video_id` as metadata too. + + A short javascript example is shown below, based on tus-js-client. Variable + "data" below is the result of this API request. Please, note that we support 2.x + version only of tus-js-client. + + ``` + uploads[data.video.id] = new tus.Upload(file, { + endpoint: `https://${data.servers[0].hostname}/upload/`, + metadata: { + filename: data.video.name, + token: data.token, + video_id: data.video.id, + client_id: data.video.client_id + }, + onSuccess: function() { + ... + } + } + uploads[data.video.id].start(); + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/streaming/videos/{video_id}/upload", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DirectUploadParameters, + ) + + def list_names( + self, + *, + ids: Iterable[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Returns names for specified video IDs + + Args: + ids: Comma-separated set of video IDs. Example, ?ids=7,17 + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._get( + "/streaming/videos/names", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"ids": ids}, video_list_names_params.VideoListNamesParams), + ), + cast_to=NoneType, + ) + + +class AsyncVideosResource(AsyncAPIResource): + @cached_property + def subtitles(self) -> AsyncSubtitlesResource: + return AsyncSubtitlesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncVideosResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncVideosResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncVideosResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncVideosResourceWithStreamingResponse(self) + + async def create( + self, + *, + video: CreateVideoParam | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VideoCreateResponse: + """ + Use this method to create a new video entity. + + **Methods of creating** + + To upload the original video file to the server, there are several possible + scenarios: + + - **Copy from another server** – If your video is accessable via "http://", + "https://", or "sftp://" public link, then you can use this method to copy a + file from an external server. Set `origin_url` parameter with the link to the + original video file (i.e. "https://domain.com/video.mp4"). After method + execution file will be uploaded and will be sent to transcoding automatically, + you don't have to do anything else. Use extra field `origin_http_headers` if + authorization is required on the external server. + - **Direct upload from a local device** – If you need to upload video directly + from your local device or from a mobile app, then use this method. Keep + `origin_url` empty and use TUS protocol ([tus.io](https://tus.io)) to upload + file. More details are here + ["Get TUS' upload"](/docs/api-reference/streaming/videos/get-tus-parameters-for-direct-upload) + + After getting the video, it is processed through the queue. There are 2 priority + criteria: global and local. Global is determined automatically by the system as + converters are ready to get next video, so your videos rarely queue longer than + usual (when you don't have a dedicated region). Local priority works at the + level of your account and you have full control over it, look at "priority" + attribute. + + **AI processing** + + When uploading a video, it is possible to automatically create subtitles based + on AI. + + Read more: + + - What is + ["AI Speech Recognition"](/docs/api-reference/streaming/ai/create-ai-asr-task). + - If the option is enabled via + `auto_transcribe_audio_language: auto|`, then immediately after + successful transcoding, an AI task will be automatically created for + transcription. + - If you need to translate subtitles from original language to any other, then + AI-task of subtitles translation can be applied. Use + `auto_translate_subtitles_language: default|` parameter for + that. Also you can point several languages to translate to, then a separate + subtitle will be generated for each specified language. + - How to + ["add AI-generated subtitles to an exist video"](/docs/api-reference/streaming/subtitles/add-subtitle). + + The created AI-task(s) will be automatically executed, and result will also be + automatically attached to this video as subtitle(s). + + Please note that transcription is done automatically for all videos uploaded to + our video hosting. If necessary, you can disable automatic creation of + subtitles. If AI is disabled in your account, no AI functionality is called. + + **Advanced Features** For details on the requirements for incoming original + files, and output video parameters after transcoding, refer to the Knowledge + Base documentation. By default video will be transcoded according to the + original resolution, and a quality ladder suitable for your original video will + be applied. There is no automatic upscaling; the maximum quality is taken from + the original video. If you want to upload specific files not explicitly listed + in requirements or wish to modify the standard quality ladder (i.e. decrease + quality or add new non-standard qualities), then such customization is possible. + Please reach out to us for assistance. + + Additionally, check the Knowledge Base for any supplementary information you may + need. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/streaming/videos", + body=await async_maybe_transform({"video": video}, video_create_params.VideoCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VideoCreateResponse, + ) + + async def update( + self, + video_id: int, + *, + name: str, + auto_transcribe_audio_language: Literal["disable", "auto", ""] | Omit = omit, + auto_translate_subtitles_language: Literal["disable", "default", ""] | Omit = omit, + client_user_id: int | Omit = omit, + clip_duration_seconds: int | Omit = omit, + clip_start_seconds: int | Omit = omit, + custom_iframe_url: str | Omit = omit, + description: str | Omit = omit, + directory_id: int | Omit = omit, + origin_http_headers: str | Omit = omit, + origin_url: str | Omit = omit, + poster: str | Omit = omit, + priority: int | Omit = omit, + projection: str | Omit = omit, + quality_set_id: int | Omit = omit, + remote_poster_url: str | Omit = omit, + remove_poster: bool | Omit = omit, + screenshot_id: int | Omit = omit, + share_url: str | Omit = omit, + source_bitrate_limit: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Changes parameters of the video to new values. + + It's allowed to update only those public parameters that are described in POST + method to create a new “video” entity. So it's not possible to change calculated + parameters like "id", "duration", "hls_url", etc. + + Examples of changing: + + - Name: `{ "name": "new name of the video" }` + - Move the video to a new directory: ` { "directory_id": 200 }` + + Please note that some parameters are used on initial step (before transcoding) + only, so after transcoding there is no use in changing their values. For + example, "origin_url" parameter is used for downloading an original file from a + source and never used after transcoding; or "priority" parameter is used to set + priority of processing and never used after transcoding. + + Args: + name: Video name + + auto_transcribe_audio_language: Automatic creation of subtitles by transcribing the audio track. + + Values: + + - disable – Do not transcribe. + - auto – Automatically detects the activation of the option based on the + settings in your account. If generation is activated, then automatic language + detection while transcribing. + - \\ – Transcribe from specific language. Can be used to specify the exact + language spoken in the audio track, or when auto language detection fails. + Language is set by 3-letter language code according to ISO-639-2 + (bibliographic code). List of languages is available in `audio_language` + attribute of API POST /streaming/ai/transcribe . + + Example: + + ``` + auto_transcribe_audio_language: "auto" + auto_transcribe_audio_language: "ger" + ``` + + More details: + + - List of AI tasks – API + [GET /streaming/ai/tasks](/docs/api-reference/streaming/ai/get-list-of-ai-tasks) + - Add subtitles to an exist video – API + [POST /streaming/videos/{`video_id`}/subtitles](/docs/api-reference/streaming/subtitles/add-subtitle). + + auto_translate_subtitles_language: Automatic translation of auto-transcribed subtitles to the specified + language(s). Can be used both together with `auto_transcribe_audio_language` + option only. + + Use it when you want to make automatic subtitles in languages other than the + original language in audio. + + Values: + + - disable – Do not translate. + - default – There are 3 default languages: eng,fre,ger + - \\ – Explicit language to translate to, or list of languages separated by a + comma. Look at list of available languages in description of AI ASR task + creation. + + If several languages are specified for translation, a separate subtitle will be + generated for each language. + + Example: + + ``` + auto_translate_subtitles_language: default + auto_translate_subtitles_language: eng,fre,ger + ``` + + Please note that subtitle translation is done separately and after + transcription. Thus separate AI-tasks are created for translation. + + client_user_id: Custom field where you can specify user ID in your system + + clip_duration_seconds: The length of the trimmed segment to transcode, instead of the entire length of + the video. Is only used in conjunction with specifying the start of a segment. + Transcoding duration is a number in seconds. + + clip_start_seconds: If you want to transcode only a trimmed segment of a video instead of entire + length if the video, then you can provide timecodes of starting point and + duration of a segment to process. Start encoding from is a number in seconds. + + custom_iframe_url: Deprecated. + + Custom URL of IFrame for video player to be used in share panel in player. Auto + generated IFrame URL provided by default + + description: Video details; not visible to the end-users + + directory_id: ID of the directory where the video should be uploaded. (beta) + + origin_http_headers: Authorization HTTP request header. Will be used as credentials to authenticate a + request to download a file (specified in "origin_url" parameter) on an external + server. + + Syntax: `Authorization: ` + + Examples: + + - "origin_http_headers": "Authorization: Basic ..." + - "origin_http_headers": "Authorization: Bearer ..." + - "origin_http_headers": "Authorization: APIKey ..." Example of usage when + downloading a file from Google Drive: + + ``` + POST https://api.gcore.com/streaming/videos + + "video": { + "name": "IBC 2024 intro.mp4", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "origin_http_headers": "Authorization: Bearer ABC" + } + ``` + + origin_url: URL to an original file which you want to copy from external storage. If + specified, system will download the file and will use it as video source for + transcoding. + + poster: Poster is your own static image which can be displayed before the video starts. + + After uploading the video, the system will automatically create several + screenshots (they will be stored in "screenshots" attribute) from which you can + select an default screenshot. This "poster" field is for uploading your own + image. Also use attribute "screenshot_id" to select poster as a default + screnshot. + + Attribute accepts single image as base64-encoded string + [(RFC 2397 – The "data" URL scheme)](https://www.rfc-editor.org/rfc/rfc2397). In + format: `data:[];base64,` + + MIME-types are image/jpeg, image/webp, and image/png and file sizes up to 1Mb. + + Examples: + + - `data:image/jpeg;base64,/9j/4AA...qf/2Q==` + - `data:image/png;base64,iVBORw0KGg...ggg==` + - `data:image/webp;base64,UklGRt.../DgAAAAA` + + priority: Priority allows you to adjust the urgency of processing some videos before + others in your account, if your algorithm requires it. For example, when there + are very urgent video and some regular ones that can wait in the queue. + + Value range, integer [-10..10]. -10 is the lowest down-priority, 10 is the + highest up-priority. Default priority is 0. + + projection: Deprecated. + + Regulates the video format: + + - **regular** — plays the video as usual + - **vr360** — plays the video in 360 degree mode + - **vr180** — plays the video in 180 degree mode + - **vr360tb** — plays the video in 3D 360 degree mode Top-Bottom. + + Default is regular + + quality_set_id: Custom quality set ID for transcoding, if transcoding is required according to + your conditions. Look at GET /`quality_sets` method + + remote_poster_url: Poster URL to download from external resource, instead of uploading via "poster" + attribute. + + It has the same restrictions as "poster" attribute. + + remove_poster: Set it to true to remove poster + + screenshot_id: Default screenshot index. + + Specify an ID from the "screenshots" array, so that the URL of the required + screenshot appears in the "screenshot" attribute as the default screenshot. By + default 5 static screenshots will be taken from different places in the video + after transcoding. If the video is short, there may be fewer screenshots. + + Counting from 0. A value of -1 sets the default screenshot to the URL of your + own image from the "poster" attribute. + + Look at "screenshot" attribute in GET /videos/{`video_id`} for details. + + share_url: Deprecated. + + Custom URL or iframe displayed in the link field when a user clicks on a sharing + button in player. If empty, the link field and social network sharing is + disabled + + source_bitrate_limit: The option allows you to set the video transcoding rule so that the output + bitrate in ABR ladder is not exceeding the bitrate of the original video. + + This option is for advanced users only. + + By default `source_bitrate_limit: true` this option allows you to have the + output bitrate not more than in the original video, thus to transcode video + faster and to deliver it to end-viewers faster as well. At the same time, the + quality will be similar to the original. + + If for some reason you need more byte-space in the output quality when encoding, + you can set this option to `source_bitrate_limit: false`. Then, when + transcoding, the quality ceiling will be raised from the bitrate of the original + video to the maximum possible limit specified in our the Product Documentation. + For example, this may be needed when: + + - to improve the visual quality parameters using PSNR, SSIM, VMAF metrics, + - to improve the picture quality on dynamic scenes, + - etc. + + The option is applied only at the video creation stage and cannot be changed + later. If you want to re-transcode the video using new value, then you need to + create and upload a new video only. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/streaming/videos/{video_id}", + body=await async_maybe_transform( + { + "name": name, + "auto_transcribe_audio_language": auto_transcribe_audio_language, + "auto_translate_subtitles_language": auto_translate_subtitles_language, + "client_user_id": client_user_id, + "clip_duration_seconds": clip_duration_seconds, + "clip_start_seconds": clip_start_seconds, + "custom_iframe_url": custom_iframe_url, + "description": description, + "directory_id": directory_id, + "origin_http_headers": origin_http_headers, + "origin_url": origin_url, + "poster": poster, + "priority": priority, + "projection": projection, + "quality_set_id": quality_set_id, + "remote_poster_url": remote_poster_url, + "remove_poster": remove_poster, + "screenshot_id": screenshot_id, + "share_url": share_url, + "source_bitrate_limit": source_bitrate_limit, + }, + video_update_params.VideoUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + def list( + self, + *, + id: str | Omit = omit, + client_user_id: int | Omit = omit, + fields: str | Omit = omit, + page: int | Omit = omit, + per_page: int | Omit = omit, + search: str | Omit = omit, + status: str | Omit = omit, + stream_id: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Video, AsyncPageStreaming[Video]]: + """ + Returns a set of videos by the given criteria. + + Args: + id: IDs of the videos to find. You can specify one or more identifiers separated by + commas. Example, ?id=1,101,1001 + + client_user_id: Find videos where "client_user_id" meta field is equal to the search value + + fields: Restriction to return only the specified attributes, instead of the entire + dataset. Specify, if you need to get short response. The following fields are + available for specifying: id, name, duration, status, `created_at`, + `updated_at`, `hls_url`, screenshots, `converted_videos`, priority, `stream_id`. + Example, ?fields=id,name,`hls_url` + + page: Page number. Use it to list the paginated content + + per_page: Items per page number. Use it to list the paginated content + + search: Aggregated search condition. If set, the video list is filtered by one combined + SQL criterion: + + - id={s} OR slug={s} OR name like {s} + + i.e. "/videos?search=1000" returns list of videos where id=1000 or slug=1000 or + name contains "1000". + + status: + Use it to get videos filtered by their status. Possible values: + + - empty + - pending + - viewable + - ready + - error + + stream_id: Find videos recorded from a specific stream, so for which "stream_id" field is + equal to the search value + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/streaming/videos", + page=AsyncPageStreaming[Video], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "id": id, + "client_user_id": client_user_id, + "fields": fields, + "page": page, + "per_page": per_page, + "search": search, + "status": status, + "stream_id": stream_id, + }, + video_list_params.VideoListParams, + ), + ), + model=Video, + ) + + async def delete( + self, + video_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Operation to delete video entity. + + When you delete a video, all transcoded qualities and all associated files such + as subtitles and screenshots, as well as other data, are deleted from cloud + storage. + + The video is deleted permanently and irreversibly. Therefore, it is impossible + to restore files after this. + + For detailed information and information on calculating your maximum monthly + storage usage, please refer to the Product Documentation. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/streaming/videos/{video_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def create_multiple( + self, + *, + fields: str | Omit = omit, + videos: Iterable[video_create_multiple_params.Video] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VideoCreateMultipleResponse: + """Mass upload of your videos. + + Method is used to set the task of creating videos in + the form of 1 aggregated request instead of a large number of single requests. + + An additional advantage is the ability to specify subtitles in the same request. + Whereas for a normal single upload, subtitles are uploaded in separate requests. + + All videos in the request will be processed in queue in order of priority. Use + "priority" attribute and look at general description in POST /videos method. + + Limits: + + - Batch max size = 500 videos. + - Max body size (payload) = 64MB. + - API connection timeout = 30 sec. + + Args: + fields: Restriction to return only the specified attributes, instead of the entire + dataset. Specify, if you need to get short response. The following fields are + available for specifying: id, name, duration, status, `created_at`, + `updated_at`, `hls_url`, screenshots, `converted_videos`, priority. Example, + ?fields=id,name,`hls_url` + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/streaming/videos/batch", + body=await async_maybe_transform( + {"videos": videos}, video_create_multiple_params.VideoCreateMultipleParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"fields": fields}, video_create_multiple_params.VideoCreateMultipleParams + ), + ), + cast_to=VideoCreateMultipleResponse, + ) + + async def get( + self, + video_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Video: + """ + Information about a video entity. + + Contains all the data about the video: meta-data, data for streaming and + renditions, static media data, data about original video. + + You can use different methods to play video: + + - `iframe_url` – a URL to a built-in HTML video player with automatically + configured video playback. + - `hls_url` – a URLs to HLS TS .m3u8 manifest, which can be played in video + players. + - `hls_cmaf_url` – a URL to HLS CMAF .m3u8 manifest with chunks in fMP4 format, + which can be played in most modern video players. + - `dash_url` – a URL to MPEG-DASH .mpd manifest, which can be played in most + modern video players. Preferable for Android and Windows devices. + - `converted_videos`/`mp4_url` – a URL to MP4 file of specific rendition. + + ![Video player](https://demo-files.gvideo.io/apidocs/coffee-run-player.jpg) + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/videos/{video_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Video, + ) + + async def get_parameters_for_direct_upload( + self, + video_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DirectUploadParameters: + """ + Use this method to get TUS' session parameters: hostname of the server to + upload, secure token. + + The general sequence of actions for a direct upload of a video is as follows: + + - Create video entity via POST method + ["Create video"](/docs/api-reference/streaming/videos/create-video) + - Get TUS' session parameters (you are here now) + - Upload file via TUS client, choose your implementation on + [tus.io](https://tus.io/implementations) + + Final endpoint for uploading is constructed using the following template: + "https://{hostname}/upload/". Also you have to provide token, `client_id`, + `video_id` as metadata too. + + A short javascript example is shown below, based on tus-js-client. Variable + "data" below is the result of this API request. Please, note that we support 2.x + version only of tus-js-client. + + ``` + uploads[data.video.id] = new tus.Upload(file, { + endpoint: `https://${data.servers[0].hostname}/upload/`, + metadata: { + filename: data.video.name, + token: data.token, + video_id: data.video.id, + client_id: data.video.client_id + }, + onSuccess: function() { + ... + } + } + uploads[data.video.id].start(); + ``` + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/streaming/videos/{video_id}/upload", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DirectUploadParameters, + ) + + async def list_names( + self, + *, + ids: Iterable[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Returns names for specified video IDs + + Args: + ids: Comma-separated set of video IDs. Example, ?ids=7,17 + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._get( + "/streaming/videos/names", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"ids": ids}, video_list_names_params.VideoListNamesParams), + ), + cast_to=NoneType, + ) + + +class VideosResourceWithRawResponse: + def __init__(self, videos: VideosResource) -> None: + self._videos = videos + + self.create = to_raw_response_wrapper( + videos.create, + ) + self.update = to_raw_response_wrapper( + videos.update, + ) + self.list = to_raw_response_wrapper( + videos.list, + ) + self.delete = to_raw_response_wrapper( + videos.delete, + ) + self.create_multiple = to_raw_response_wrapper( + videos.create_multiple, + ) + self.get = to_raw_response_wrapper( + videos.get, + ) + self.get_parameters_for_direct_upload = to_raw_response_wrapper( + videos.get_parameters_for_direct_upload, + ) + self.list_names = to_raw_response_wrapper( + videos.list_names, + ) + + @cached_property + def subtitles(self) -> SubtitlesResourceWithRawResponse: + return SubtitlesResourceWithRawResponse(self._videos.subtitles) + + +class AsyncVideosResourceWithRawResponse: + def __init__(self, videos: AsyncVideosResource) -> None: + self._videos = videos + + self.create = async_to_raw_response_wrapper( + videos.create, + ) + self.update = async_to_raw_response_wrapper( + videos.update, + ) + self.list = async_to_raw_response_wrapper( + videos.list, + ) + self.delete = async_to_raw_response_wrapper( + videos.delete, + ) + self.create_multiple = async_to_raw_response_wrapper( + videos.create_multiple, + ) + self.get = async_to_raw_response_wrapper( + videos.get, + ) + self.get_parameters_for_direct_upload = async_to_raw_response_wrapper( + videos.get_parameters_for_direct_upload, + ) + self.list_names = async_to_raw_response_wrapper( + videos.list_names, + ) + + @cached_property + def subtitles(self) -> AsyncSubtitlesResourceWithRawResponse: + return AsyncSubtitlesResourceWithRawResponse(self._videos.subtitles) + + +class VideosResourceWithStreamingResponse: + def __init__(self, videos: VideosResource) -> None: + self._videos = videos + + self.create = to_streamed_response_wrapper( + videos.create, + ) + self.update = to_streamed_response_wrapper( + videos.update, + ) + self.list = to_streamed_response_wrapper( + videos.list, + ) + self.delete = to_streamed_response_wrapper( + videos.delete, + ) + self.create_multiple = to_streamed_response_wrapper( + videos.create_multiple, + ) + self.get = to_streamed_response_wrapper( + videos.get, + ) + self.get_parameters_for_direct_upload = to_streamed_response_wrapper( + videos.get_parameters_for_direct_upload, + ) + self.list_names = to_streamed_response_wrapper( + videos.list_names, + ) + + @cached_property + def subtitles(self) -> SubtitlesResourceWithStreamingResponse: + return SubtitlesResourceWithStreamingResponse(self._videos.subtitles) + + +class AsyncVideosResourceWithStreamingResponse: + def __init__(self, videos: AsyncVideosResource) -> None: + self._videos = videos + + self.create = async_to_streamed_response_wrapper( + videos.create, + ) + self.update = async_to_streamed_response_wrapper( + videos.update, + ) + self.list = async_to_streamed_response_wrapper( + videos.list, + ) + self.delete = async_to_streamed_response_wrapper( + videos.delete, + ) + self.create_multiple = async_to_streamed_response_wrapper( + videos.create_multiple, + ) + self.get = async_to_streamed_response_wrapper( + videos.get, + ) + self.get_parameters_for_direct_upload = async_to_streamed_response_wrapper( + videos.get_parameters_for_direct_upload, + ) + self.list_names = async_to_streamed_response_wrapper( + videos.list_names, + ) + + @cached_property + def subtitles(self) -> AsyncSubtitlesResourceWithStreamingResponse: + return AsyncSubtitlesResourceWithStreamingResponse(self._videos.subtitles) diff --git a/src/gcore/resources/waap/__init__.py b/src/gcore/resources/waap/__init__.py new file mode 100644 index 00000000..cb4dfc95 --- /dev/null +++ b/src/gcore/resources/waap/__init__.py @@ -0,0 +1,131 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .tags import ( + TagsResource, + AsyncTagsResource, + TagsResourceWithRawResponse, + AsyncTagsResourceWithRawResponse, + TagsResourceWithStreamingResponse, + AsyncTagsResourceWithStreamingResponse, +) +from .waap import ( + WaapResource, + AsyncWaapResource, + WaapResourceWithRawResponse, + AsyncWaapResourceWithRawResponse, + WaapResourceWithStreamingResponse, + AsyncWaapResourceWithStreamingResponse, +) +from .domains import ( + DomainsResource, + AsyncDomainsResource, + DomainsResourceWithRawResponse, + AsyncDomainsResourceWithRawResponse, + DomainsResourceWithStreamingResponse, + AsyncDomainsResourceWithStreamingResponse, +) +from .ip_info import ( + IPInfoResource, + AsyncIPInfoResource, + IPInfoResourceWithRawResponse, + AsyncIPInfoResourceWithRawResponse, + IPInfoResourceWithStreamingResponse, + AsyncIPInfoResourceWithStreamingResponse, +) +from .insights import ( + InsightsResource, + AsyncInsightsResource, + InsightsResourceWithRawResponse, + AsyncInsightsResourceWithRawResponse, + InsightsResourceWithStreamingResponse, + AsyncInsightsResourceWithStreamingResponse, +) +from .statistics import ( + StatisticsResource, + AsyncStatisticsResource, + StatisticsResourceWithRawResponse, + AsyncStatisticsResourceWithRawResponse, + StatisticsResourceWithStreamingResponse, + AsyncStatisticsResourceWithStreamingResponse, +) +from .organizations import ( + OrganizationsResource, + AsyncOrganizationsResource, + OrganizationsResourceWithRawResponse, + AsyncOrganizationsResourceWithRawResponse, + OrganizationsResourceWithStreamingResponse, + AsyncOrganizationsResourceWithStreamingResponse, +) +from .advanced_rules import ( + AdvancedRulesResource, + AsyncAdvancedRulesResource, + AdvancedRulesResourceWithRawResponse, + AsyncAdvancedRulesResourceWithRawResponse, + AdvancedRulesResourceWithStreamingResponse, + AsyncAdvancedRulesResourceWithStreamingResponse, +) +from .custom_page_sets import ( + CustomPageSetsResource, + AsyncCustomPageSetsResource, + CustomPageSetsResourceWithRawResponse, + AsyncCustomPageSetsResourceWithRawResponse, + CustomPageSetsResourceWithStreamingResponse, + AsyncCustomPageSetsResourceWithStreamingResponse, +) + +__all__ = [ + "StatisticsResource", + "AsyncStatisticsResource", + "StatisticsResourceWithRawResponse", + "AsyncStatisticsResourceWithRawResponse", + "StatisticsResourceWithStreamingResponse", + "AsyncStatisticsResourceWithStreamingResponse", + "DomainsResource", + "AsyncDomainsResource", + "DomainsResourceWithRawResponse", + "AsyncDomainsResourceWithRawResponse", + "DomainsResourceWithStreamingResponse", + "AsyncDomainsResourceWithStreamingResponse", + "CustomPageSetsResource", + "AsyncCustomPageSetsResource", + "CustomPageSetsResourceWithRawResponse", + "AsyncCustomPageSetsResourceWithRawResponse", + "CustomPageSetsResourceWithStreamingResponse", + "AsyncCustomPageSetsResourceWithStreamingResponse", + "AdvancedRulesResource", + "AsyncAdvancedRulesResource", + "AdvancedRulesResourceWithRawResponse", + "AsyncAdvancedRulesResourceWithRawResponse", + "AdvancedRulesResourceWithStreamingResponse", + "AsyncAdvancedRulesResourceWithStreamingResponse", + "TagsResource", + "AsyncTagsResource", + "TagsResourceWithRawResponse", + "AsyncTagsResourceWithRawResponse", + "TagsResourceWithStreamingResponse", + "AsyncTagsResourceWithStreamingResponse", + "OrganizationsResource", + "AsyncOrganizationsResource", + "OrganizationsResourceWithRawResponse", + "AsyncOrganizationsResourceWithRawResponse", + "OrganizationsResourceWithStreamingResponse", + "AsyncOrganizationsResourceWithStreamingResponse", + "InsightsResource", + "AsyncInsightsResource", + "InsightsResourceWithRawResponse", + "AsyncInsightsResourceWithRawResponse", + "InsightsResourceWithStreamingResponse", + "AsyncInsightsResourceWithStreamingResponse", + "IPInfoResource", + "AsyncIPInfoResource", + "IPInfoResourceWithRawResponse", + "AsyncIPInfoResourceWithRawResponse", + "IPInfoResourceWithStreamingResponse", + "AsyncIPInfoResourceWithStreamingResponse", + "WaapResource", + "AsyncWaapResource", + "WaapResourceWithRawResponse", + "AsyncWaapResourceWithRawResponse", + "WaapResourceWithStreamingResponse", + "AsyncWaapResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/waap/advanced_rules.py b/src/gcore/resources/waap/advanced_rules.py new file mode 100644 index 00000000..6f4aca32 --- /dev/null +++ b/src/gcore/resources/waap/advanced_rules.py @@ -0,0 +1,135 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.waap.waap_advanced_rule_descriptor_list import WaapAdvancedRuleDescriptorList + +__all__ = ["AdvancedRulesResource", "AsyncAdvancedRulesResource"] + + +class AdvancedRulesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> AdvancedRulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AdvancedRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AdvancedRulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AdvancedRulesResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAdvancedRuleDescriptorList: + """Retrieve an advanced rules descriptor""" + return self._get( + "/waap/v1/advanced-rules/descriptor", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAdvancedRuleDescriptorList, + ) + + +class AsyncAdvancedRulesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAdvancedRulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncAdvancedRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAdvancedRulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncAdvancedRulesResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAdvancedRuleDescriptorList: + """Retrieve an advanced rules descriptor""" + return await self._get( + "/waap/v1/advanced-rules/descriptor", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAdvancedRuleDescriptorList, + ) + + +class AdvancedRulesResourceWithRawResponse: + def __init__(self, advanced_rules: AdvancedRulesResource) -> None: + self._advanced_rules = advanced_rules + + self.list = to_raw_response_wrapper( + advanced_rules.list, + ) + + +class AsyncAdvancedRulesResourceWithRawResponse: + def __init__(self, advanced_rules: AsyncAdvancedRulesResource) -> None: + self._advanced_rules = advanced_rules + + self.list = async_to_raw_response_wrapper( + advanced_rules.list, + ) + + +class AdvancedRulesResourceWithStreamingResponse: + def __init__(self, advanced_rules: AdvancedRulesResource) -> None: + self._advanced_rules = advanced_rules + + self.list = to_streamed_response_wrapper( + advanced_rules.list, + ) + + +class AsyncAdvancedRulesResourceWithStreamingResponse: + def __init__(self, advanced_rules: AsyncAdvancedRulesResource) -> None: + self._advanced_rules = advanced_rules + + self.list = async_to_streamed_response_wrapper( + advanced_rules.list, + ) diff --git a/src/gcore/resources/waap/api.md b/src/gcore/resources/waap/api.md new file mode 100644 index 00000000..52a55dc6 --- /dev/null +++ b/src/gcore/resources/waap/api.md @@ -0,0 +1,322 @@ +# Waap + +Types: + +```python +from gcore.types.waap import WaapGetAccountOverviewResponse +``` + +Methods: + +- client.waap.get_account_overview() -> WaapGetAccountOverviewResponse + +## Statistics + +Types: + +```python +from gcore.types.waap import WaapStatisticItem, WaapStatisticsSeries +``` + +Methods: + +- client.waap.statistics.get_usage_series(\*\*params) -> WaapStatisticsSeries + +## Domains + +Types: + +```python +from gcore.types.waap import ( + WaapDetailedDomain, + WaapDomainAPISettings, + WaapDomainDDOSSettings, + WaapDomainSettingsModel, + WaapPolicyMode, + WaapRuleSet, + WaapSummaryDomain, + DomainListRuleSetsResponse, +) +``` + +Methods: + +- client.waap.domains.update(domain_id, \*\*params) -> None +- client.waap.domains.list(\*\*params) -> SyncOffsetPage[WaapSummaryDomain] +- client.waap.domains.delete(domain_id) -> None +- client.waap.domains.get(domain_id) -> WaapDetailedDomain +- client.waap.domains.list_rule_sets(domain_id) -> DomainListRuleSetsResponse +- client.waap.domains.toggle_policy(policy_id, \*, domain_id) -> WaapPolicyMode + +### Settings + +Methods: + +- client.waap.domains.settings.update(domain_id, \*\*params) -> None +- client.waap.domains.settings.get(domain_id) -> WaapDomainSettingsModel + +### APIPaths + +Types: + +```python +from gcore.types.waap.domains import WaapAPIPath +``` + +Methods: + +- client.waap.domains.api_paths.create(domain_id, \*\*params) -> WaapAPIPath +- client.waap.domains.api_paths.update(path_id, \*, domain_id, \*\*params) -> None +- client.waap.domains.api_paths.list(domain_id, \*\*params) -> SyncOffsetPage[WaapAPIPath] +- client.waap.domains.api_paths.delete(path_id, \*, domain_id) -> None +- client.waap.domains.api_paths.get(path_id, \*, domain_id) -> WaapAPIPath + +### APIPathGroups + +Types: + +```python +from gcore.types.waap.domains import APIPathGroupList +``` + +Methods: + +- client.waap.domains.api_path_groups.list(domain_id) -> APIPathGroupList + +### APIDiscovery + +Types: + +```python +from gcore.types.waap.domains import WaapAPIDiscoverySettings, WaapAPIScanResult, WaapTaskID +``` + +Methods: + +- client.waap.domains.api_discovery.get_scan_result(scan_id, \*, domain_id) -> WaapAPIScanResult +- client.waap.domains.api_discovery.get_settings(domain_id) -> WaapAPIDiscoverySettings +- client.waap.domains.api_discovery.list_scan_results(domain_id, \*\*params) -> SyncOffsetPage[WaapAPIScanResult] +- client.waap.domains.api_discovery.scan_openapi(domain_id) -> WaapTaskID +- client.waap.domains.api_discovery.update_settings(domain_id, \*\*params) -> WaapAPIDiscoverySettings +- client.waap.domains.api_discovery.upload_openapi(domain_id, \*\*params) -> WaapTaskID + +### Insights + +Types: + +```python +from gcore.types.waap.domains import WaapInsight +``` + +Methods: + +- client.waap.domains.insights.list(domain_id, \*\*params) -> SyncOffsetPage[WaapInsight] +- client.waap.domains.insights.get(insight_id, \*, domain_id) -> WaapInsight +- client.waap.domains.insights.replace(insight_id, \*, domain_id, \*\*params) -> WaapInsight + +### InsightSilences + +Types: + +```python +from gcore.types.waap.domains import WaapInsightSilence +``` + +Methods: + +- client.waap.domains.insight_silences.create(domain_id, \*\*params) -> WaapInsightSilence +- client.waap.domains.insight_silences.update(silence_id, \*, domain_id, \*\*params) -> WaapInsightSilence +- client.waap.domains.insight_silences.list(domain_id, \*\*params) -> SyncOffsetPage[WaapInsightSilence] +- client.waap.domains.insight_silences.delete(silence_id, \*, domain_id) -> None +- client.waap.domains.insight_silences.get(silence_id, \*, domain_id) -> WaapInsightSilence + +### Statistics + +Types: + +```python +from gcore.types.waap.domains import ( + WaapBlockedStatistics, + WaapCountStatistics, + WaapDDOSAttack, + WaapDDOSInfo, + WaapEventStatistics, + WaapRequestDetails, + WaapRequestSummary, + WaapTrafficMetrics, + StatisticGetTrafficSeriesResponse, +) +``` + +Methods: + +- client.waap.domains.statistics.get_ddos_attacks(domain_id, \*\*params) -> SyncOffsetPage[WaapDDOSAttack] +- client.waap.domains.statistics.get_ddos_info(domain_id, \*\*params) -> SyncOffsetPage[WaapDDOSInfo] +- client.waap.domains.statistics.get_events_aggregated(domain_id, \*\*params) -> WaapEventStatistics +- client.waap.domains.statistics.get_request_details(request_id, \*, domain_id) -> WaapRequestDetails +- client.waap.domains.statistics.get_requests_series(domain_id, \*\*params) -> SyncOffsetPage[WaapRequestSummary] +- client.waap.domains.statistics.get_traffic_series(domain_id, \*\*params) -> StatisticGetTrafficSeriesResponse + +### CustomRules + +Types: + +```python +from gcore.types.waap.domains import WaapCustomRule +``` + +Methods: + +- client.waap.domains.custom_rules.create(domain_id, \*\*params) -> WaapCustomRule +- client.waap.domains.custom_rules.update(rule_id, \*, domain_id, \*\*params) -> None +- client.waap.domains.custom_rules.list(domain_id, \*\*params) -> SyncOffsetPage[WaapCustomRule] +- client.waap.domains.custom_rules.delete(rule_id, \*, domain_id) -> None +- client.waap.domains.custom_rules.delete_multiple(domain_id, \*\*params) -> None +- client.waap.domains.custom_rules.get(rule_id, \*, domain_id) -> WaapCustomRule +- client.waap.domains.custom_rules.toggle(action, \*, domain_id, rule_id) -> None + +### FirewallRules + +Types: + +```python +from gcore.types.waap.domains import WaapFirewallRule +``` + +Methods: + +- client.waap.domains.firewall_rules.create(domain_id, \*\*params) -> WaapFirewallRule +- client.waap.domains.firewall_rules.update(rule_id, \*, domain_id, \*\*params) -> None +- client.waap.domains.firewall_rules.list(domain_id, \*\*params) -> SyncOffsetPage[WaapFirewallRule] +- client.waap.domains.firewall_rules.delete(rule_id, \*, domain_id) -> None +- client.waap.domains.firewall_rules.delete_multiple(domain_id, \*\*params) -> None +- client.waap.domains.firewall_rules.get(rule_id, \*, domain_id) -> WaapFirewallRule +- client.waap.domains.firewall_rules.toggle(action, \*, domain_id, rule_id) -> None + +### AdvancedRules + +Types: + +```python +from gcore.types.waap.domains import WaapAdvancedRule +``` + +Methods: + +- client.waap.domains.advanced_rules.create(domain_id, \*\*params) -> WaapAdvancedRule +- client.waap.domains.advanced_rules.update(rule_id, \*, domain_id, \*\*params) -> None +- client.waap.domains.advanced_rules.list(domain_id, \*\*params) -> SyncOffsetPage[WaapAdvancedRule] +- client.waap.domains.advanced_rules.delete(rule_id, \*, domain_id) -> None +- client.waap.domains.advanced_rules.get(rule_id, \*, domain_id) -> WaapAdvancedRule +- client.waap.domains.advanced_rules.toggle(action, \*, domain_id, rule_id) -> None + +## CustomPageSets + +Types: + +```python +from gcore.types.waap import WaapCustomPagePreview, WaapCustomPageSet +``` + +Methods: + +- client.waap.custom_page_sets.create(\*\*params) -> WaapCustomPageSet +- client.waap.custom_page_sets.update(set_id, \*\*params) -> None +- client.waap.custom_page_sets.list(\*\*params) -> SyncOffsetPage[WaapCustomPageSet] +- client.waap.custom_page_sets.delete(set_id) -> None +- client.waap.custom_page_sets.get(set_id) -> WaapCustomPageSet +- client.waap.custom_page_sets.preview(\*\*params) -> WaapCustomPagePreview + +## AdvancedRules + +Types: + +```python +from gcore.types.waap import WaapAdvancedRuleDescriptor, WaapAdvancedRuleDescriptorList +``` + +Methods: + +- client.waap.advanced_rules.list() -> WaapAdvancedRuleDescriptorList + +## Tags + +Types: + +```python +from gcore.types.waap import WaapTag +``` + +Methods: + +- client.waap.tags.list(\*\*params) -> SyncOffsetPage[WaapTag] + +## Organizations + +Types: + +```python +from gcore.types.waap import WaapOrganization +``` + +Methods: + +- client.waap.organizations.list(\*\*params) -> SyncOffsetPage[WaapOrganization] + +## Insights + +Types: + +```python +from gcore.types.waap import WaapInsightType +``` + +Methods: + +- client.waap.insights.list_types(\*\*params) -> SyncOffsetPage[WaapInsightType] + +## IPInfo + +Types: + +```python +from gcore.types.waap import ( + WaapIPCountryAttack, + WaapIPDDOSInfoModel, + WaapIPInfo, + WaapRuleBlockedRequests, + WaapTimeSeriesAttack, + WaapTopSession, + WaapTopURL, + WaapTopUserAgent, + IPInfoGetAttackTimeSeriesResponse, + IPInfoGetBlockedRequestsResponse, + IPInfoGetTopURLsResponse, + IPInfoGetTopUserAgentsResponse, + IPInfoGetTopUserSessionsResponse, + IPInfoListAttackedCountriesResponse, +) +``` + +Methods: + +- client.waap.ip_info.get_attack_time_series(\*\*params) -> IPInfoGetAttackTimeSeriesResponse +- client.waap.ip_info.get_blocked_requests(\*\*params) -> IPInfoGetBlockedRequestsResponse +- client.waap.ip_info.get_ddos_attack_series(\*\*params) -> WaapIPDDOSInfoModel +- client.waap.ip_info.get_ip_info(\*\*params) -> WaapIPInfo +- client.waap.ip_info.get_top_urls(\*\*params) -> IPInfoGetTopURLsResponse +- client.waap.ip_info.get_top_user_agents(\*\*params) -> IPInfoGetTopUserAgentsResponse +- client.waap.ip_info.get_top_user_sessions(\*\*params) -> IPInfoGetTopUserSessionsResponse +- client.waap.ip_info.list_attacked_countries(\*\*params) -> IPInfoListAttackedCountriesResponse + +### Metrics + +Types: + +```python +from gcore.types.waap.ip_info import WaapIPInfoCounts +``` + +Methods: + +- client.waap.ip_info.metrics.list(\*\*params) -> WaapIPInfoCounts diff --git a/src/gcore/resources/waap/custom_page_sets.py b/src/gcore/resources/waap/custom_page_sets.py new file mode 100644 index 00000000..11d40a03 --- /dev/null +++ b/src/gcore/resources/waap/custom_page_sets.py @@ -0,0 +1,811 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ...types.waap import ( + custom_page_set_list_params, + custom_page_set_create_params, + custom_page_set_update_params, + custom_page_set_preview_params, +) +from ..._base_client import AsyncPaginator, make_request_options +from ...types.waap.waap_custom_page_set import WaapCustomPageSet +from ...types.waap.waap_custom_page_preview import WaapCustomPagePreview + +__all__ = ["CustomPageSetsResource", "AsyncCustomPageSetsResource"] + + +class CustomPageSetsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CustomPageSetsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return CustomPageSetsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CustomPageSetsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return CustomPageSetsResourceWithStreamingResponse(self) + + def create( + self, + *, + name: str, + block: Optional[custom_page_set_create_params.Block] | Omit = omit, + block_csrf: Optional[custom_page_set_create_params.BlockCsrf] | Omit = omit, + captcha: Optional[custom_page_set_create_params.Captcha] | Omit = omit, + cookie_disabled: Optional[custom_page_set_create_params.CookieDisabled] | Omit = omit, + domains: Optional[Iterable[int]] | Omit = omit, + handshake: Optional[custom_page_set_create_params.Handshake] | Omit = omit, + javascript_disabled: Optional[custom_page_set_create_params.JavascriptDisabled] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapCustomPageSet: + """Create a custom page set based on the provided data. + + For any custom page type + (block, `block_csrf`, etc) that is not provided the default page will be used. + + Args: + name: Name of the custom page set + + domains: List of domain IDs that are associated with this page set + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/waap/v1/custom-page-sets", + body=maybe_transform( + { + "name": name, + "block": block, + "block_csrf": block_csrf, + "captcha": captcha, + "cookie_disabled": cookie_disabled, + "domains": domains, + "handshake": handshake, + "javascript_disabled": javascript_disabled, + }, + custom_page_set_create_params.CustomPageSetCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapCustomPageSet, + ) + + def update( + self, + set_id: int, + *, + block: Optional[custom_page_set_update_params.Block] | Omit = omit, + block_csrf: Optional[custom_page_set_update_params.BlockCsrf] | Omit = omit, + captcha: Optional[custom_page_set_update_params.Captcha] | Omit = omit, + cookie_disabled: Optional[custom_page_set_update_params.CookieDisabled] | Omit = omit, + domains: Optional[Iterable[int]] | Omit = omit, + handshake: Optional[custom_page_set_update_params.Handshake] | Omit = omit, + javascript_disabled: Optional[custom_page_set_update_params.JavascriptDisabled] | Omit = omit, + name: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Update a custom page set based on the provided parameters. + + To update a field, + provide the field with the new value. To remove a field, provide it as null. To + keep a field unaltered, do not include it in the request. Note: `name` cannot be + removed. When updating a custom page, include all the fields that you want it to + have. Any field not included will be removed. + + Args: + set_id: The ID of the custom page set + + domains: List of domain IDs that are associated with this page set + + name: Name of the custom page set + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._patch( + f"/waap/v1/custom-page-sets/{set_id}", + body=maybe_transform( + { + "block": block, + "block_csrf": block_csrf, + "captcha": captcha, + "cookie_disabled": cookie_disabled, + "domains": domains, + "handshake": handshake, + "javascript_disabled": javascript_disabled, + "name": name, + }, + custom_page_set_update_params.CustomPageSetUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + *, + ids: Iterable[int] | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Literal["name", "-name", "id", "-id"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapCustomPageSet]: + """ + Retrieve a list of custom page sets available for use + + Args: + ids: Filter page sets based on their IDs + + limit: Number of items to return + + name: Filter page sets based on their name. Supports '\\**' as a wildcard character + + offset: Number of items to skip + + ordering: Sort the response by given field. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/waap/v1/custom-page-sets", + page=SyncOffsetPage[WaapCustomPageSet], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "ids": ids, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + }, + custom_page_set_list_params.CustomPageSetListParams, + ), + ), + model=WaapCustomPageSet, + ) + + def delete( + self, + set_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a custom page set + + Args: + set_id: The ID of the custom page set + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/waap/v1/custom-page-sets/{set_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + set_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapCustomPageSet: + """ + Retrieve a custom page set based on the provided ID + + Args: + set_id: The ID of the custom page set + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/waap/v1/custom-page-sets/{set_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapCustomPageSet, + ) + + def preview( + self, + *, + page_type: Literal[ + "block.html", + "block_csrf.html", + "captcha.html", + "cookieDisabled.html", + "handshake.html", + "javascriptDisabled.html", + ], + error: Optional[str] | Omit = omit, + header: Optional[str] | Omit = omit, + logo: Optional[str] | Omit = omit, + text: Optional[str] | Omit = omit, + title: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapCustomPagePreview: + """ + Allows to preview a custom page without creating it based on the provided type + and data + + Args: + page_type: The type of the custom page + + error: Error message + + header: The text to display in the header of the custom page + + logo: Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + + text: The text to display in the body of the custom page + + title: The text to display in the title of the custom page + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/waap/v1/preview-custom-page", + body=maybe_transform( + { + "error": error, + "header": header, + "logo": logo, + "text": text, + "title": title, + }, + custom_page_set_preview_params.CustomPageSetPreviewParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + {"page_type": page_type}, custom_page_set_preview_params.CustomPageSetPreviewParams + ), + ), + cast_to=WaapCustomPagePreview, + ) + + +class AsyncCustomPageSetsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCustomPageSetsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncCustomPageSetsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCustomPageSetsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncCustomPageSetsResourceWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + block: Optional[custom_page_set_create_params.Block] | Omit = omit, + block_csrf: Optional[custom_page_set_create_params.BlockCsrf] | Omit = omit, + captcha: Optional[custom_page_set_create_params.Captcha] | Omit = omit, + cookie_disabled: Optional[custom_page_set_create_params.CookieDisabled] | Omit = omit, + domains: Optional[Iterable[int]] | Omit = omit, + handshake: Optional[custom_page_set_create_params.Handshake] | Omit = omit, + javascript_disabled: Optional[custom_page_set_create_params.JavascriptDisabled] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapCustomPageSet: + """Create a custom page set based on the provided data. + + For any custom page type + (block, `block_csrf`, etc) that is not provided the default page will be used. + + Args: + name: Name of the custom page set + + domains: List of domain IDs that are associated with this page set + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/waap/v1/custom-page-sets", + body=await async_maybe_transform( + { + "name": name, + "block": block, + "block_csrf": block_csrf, + "captcha": captcha, + "cookie_disabled": cookie_disabled, + "domains": domains, + "handshake": handshake, + "javascript_disabled": javascript_disabled, + }, + custom_page_set_create_params.CustomPageSetCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapCustomPageSet, + ) + + async def update( + self, + set_id: int, + *, + block: Optional[custom_page_set_update_params.Block] | Omit = omit, + block_csrf: Optional[custom_page_set_update_params.BlockCsrf] | Omit = omit, + captcha: Optional[custom_page_set_update_params.Captcha] | Omit = omit, + cookie_disabled: Optional[custom_page_set_update_params.CookieDisabled] | Omit = omit, + domains: Optional[Iterable[int]] | Omit = omit, + handshake: Optional[custom_page_set_update_params.Handshake] | Omit = omit, + javascript_disabled: Optional[custom_page_set_update_params.JavascriptDisabled] | Omit = omit, + name: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Update a custom page set based on the provided parameters. + + To update a field, + provide the field with the new value. To remove a field, provide it as null. To + keep a field unaltered, do not include it in the request. Note: `name` cannot be + removed. When updating a custom page, include all the fields that you want it to + have. Any field not included will be removed. + + Args: + set_id: The ID of the custom page set + + domains: List of domain IDs that are associated with this page set + + name: Name of the custom page set + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._patch( + f"/waap/v1/custom-page-sets/{set_id}", + body=await async_maybe_transform( + { + "block": block, + "block_csrf": block_csrf, + "captcha": captcha, + "cookie_disabled": cookie_disabled, + "domains": domains, + "handshake": handshake, + "javascript_disabled": javascript_disabled, + "name": name, + }, + custom_page_set_update_params.CustomPageSetUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + *, + ids: Iterable[int] | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Literal["name", "-name", "id", "-id"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapCustomPageSet, AsyncOffsetPage[WaapCustomPageSet]]: + """ + Retrieve a list of custom page sets available for use + + Args: + ids: Filter page sets based on their IDs + + limit: Number of items to return + + name: Filter page sets based on their name. Supports '\\**' as a wildcard character + + offset: Number of items to skip + + ordering: Sort the response by given field. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/waap/v1/custom-page-sets", + page=AsyncOffsetPage[WaapCustomPageSet], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "ids": ids, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + }, + custom_page_set_list_params.CustomPageSetListParams, + ), + ), + model=WaapCustomPageSet, + ) + + async def delete( + self, + set_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a custom page set + + Args: + set_id: The ID of the custom page set + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/waap/v1/custom-page-sets/{set_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + set_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapCustomPageSet: + """ + Retrieve a custom page set based on the provided ID + + Args: + set_id: The ID of the custom page set + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/waap/v1/custom-page-sets/{set_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapCustomPageSet, + ) + + async def preview( + self, + *, + page_type: Literal[ + "block.html", + "block_csrf.html", + "captcha.html", + "cookieDisabled.html", + "handshake.html", + "javascriptDisabled.html", + ], + error: Optional[str] | Omit = omit, + header: Optional[str] | Omit = omit, + logo: Optional[str] | Omit = omit, + text: Optional[str] | Omit = omit, + title: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapCustomPagePreview: + """ + Allows to preview a custom page without creating it based on the provided type + and data + + Args: + page_type: The type of the custom page + + error: Error message + + header: The text to display in the header of the custom page + + logo: Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + + text: The text to display in the body of the custom page + + title: The text to display in the title of the custom page + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/waap/v1/preview-custom-page", + body=await async_maybe_transform( + { + "error": error, + "header": header, + "logo": logo, + "text": text, + "title": title, + }, + custom_page_set_preview_params.CustomPageSetPreviewParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"page_type": page_type}, custom_page_set_preview_params.CustomPageSetPreviewParams + ), + ), + cast_to=WaapCustomPagePreview, + ) + + +class CustomPageSetsResourceWithRawResponse: + def __init__(self, custom_page_sets: CustomPageSetsResource) -> None: + self._custom_page_sets = custom_page_sets + + self.create = to_raw_response_wrapper( + custom_page_sets.create, + ) + self.update = to_raw_response_wrapper( + custom_page_sets.update, + ) + self.list = to_raw_response_wrapper( + custom_page_sets.list, + ) + self.delete = to_raw_response_wrapper( + custom_page_sets.delete, + ) + self.get = to_raw_response_wrapper( + custom_page_sets.get, + ) + self.preview = to_raw_response_wrapper( + custom_page_sets.preview, + ) + + +class AsyncCustomPageSetsResourceWithRawResponse: + def __init__(self, custom_page_sets: AsyncCustomPageSetsResource) -> None: + self._custom_page_sets = custom_page_sets + + self.create = async_to_raw_response_wrapper( + custom_page_sets.create, + ) + self.update = async_to_raw_response_wrapper( + custom_page_sets.update, + ) + self.list = async_to_raw_response_wrapper( + custom_page_sets.list, + ) + self.delete = async_to_raw_response_wrapper( + custom_page_sets.delete, + ) + self.get = async_to_raw_response_wrapper( + custom_page_sets.get, + ) + self.preview = async_to_raw_response_wrapper( + custom_page_sets.preview, + ) + + +class CustomPageSetsResourceWithStreamingResponse: + def __init__(self, custom_page_sets: CustomPageSetsResource) -> None: + self._custom_page_sets = custom_page_sets + + self.create = to_streamed_response_wrapper( + custom_page_sets.create, + ) + self.update = to_streamed_response_wrapper( + custom_page_sets.update, + ) + self.list = to_streamed_response_wrapper( + custom_page_sets.list, + ) + self.delete = to_streamed_response_wrapper( + custom_page_sets.delete, + ) + self.get = to_streamed_response_wrapper( + custom_page_sets.get, + ) + self.preview = to_streamed_response_wrapper( + custom_page_sets.preview, + ) + + +class AsyncCustomPageSetsResourceWithStreamingResponse: + def __init__(self, custom_page_sets: AsyncCustomPageSetsResource) -> None: + self._custom_page_sets = custom_page_sets + + self.create = async_to_streamed_response_wrapper( + custom_page_sets.create, + ) + self.update = async_to_streamed_response_wrapper( + custom_page_sets.update, + ) + self.list = async_to_streamed_response_wrapper( + custom_page_sets.list, + ) + self.delete = async_to_streamed_response_wrapper( + custom_page_sets.delete, + ) + self.get = async_to_streamed_response_wrapper( + custom_page_sets.get, + ) + self.preview = async_to_streamed_response_wrapper( + custom_page_sets.preview, + ) diff --git a/src/gcore/resources/waap/domains/__init__.py b/src/gcore/resources/waap/domains/__init__.py new file mode 100644 index 00000000..33cc8323 --- /dev/null +++ b/src/gcore/resources/waap/domains/__init__.py @@ -0,0 +1,159 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .domains import ( + DomainsResource, + AsyncDomainsResource, + DomainsResourceWithRawResponse, + AsyncDomainsResourceWithRawResponse, + DomainsResourceWithStreamingResponse, + AsyncDomainsResourceWithStreamingResponse, +) +from .insights import ( + InsightsResource, + AsyncInsightsResource, + InsightsResourceWithRawResponse, + AsyncInsightsResourceWithRawResponse, + InsightsResourceWithStreamingResponse, + AsyncInsightsResourceWithStreamingResponse, +) +from .settings import ( + SettingsResource, + AsyncSettingsResource, + SettingsResourceWithRawResponse, + AsyncSettingsResourceWithRawResponse, + SettingsResourceWithStreamingResponse, + AsyncSettingsResourceWithStreamingResponse, +) +from .api_paths import ( + APIPathsResource, + AsyncAPIPathsResource, + APIPathsResourceWithRawResponse, + AsyncAPIPathsResourceWithRawResponse, + APIPathsResourceWithStreamingResponse, + AsyncAPIPathsResourceWithStreamingResponse, +) +from .statistics import ( + StatisticsResource, + AsyncStatisticsResource, + StatisticsResourceWithRawResponse, + AsyncStatisticsResourceWithRawResponse, + StatisticsResourceWithStreamingResponse, + AsyncStatisticsResourceWithStreamingResponse, +) +from .custom_rules import ( + CustomRulesResource, + AsyncCustomRulesResource, + CustomRulesResourceWithRawResponse, + AsyncCustomRulesResourceWithRawResponse, + CustomRulesResourceWithStreamingResponse, + AsyncCustomRulesResourceWithStreamingResponse, +) +from .api_discovery import ( + APIDiscoveryResource, + AsyncAPIDiscoveryResource, + APIDiscoveryResourceWithRawResponse, + AsyncAPIDiscoveryResourceWithRawResponse, + APIDiscoveryResourceWithStreamingResponse, + AsyncAPIDiscoveryResourceWithStreamingResponse, +) +from .advanced_rules import ( + AdvancedRulesResource, + AsyncAdvancedRulesResource, + AdvancedRulesResourceWithRawResponse, + AsyncAdvancedRulesResourceWithRawResponse, + AdvancedRulesResourceWithStreamingResponse, + AsyncAdvancedRulesResourceWithStreamingResponse, +) +from .firewall_rules import ( + FirewallRulesResource, + AsyncFirewallRulesResource, + FirewallRulesResourceWithRawResponse, + AsyncFirewallRulesResourceWithRawResponse, + FirewallRulesResourceWithStreamingResponse, + AsyncFirewallRulesResourceWithStreamingResponse, +) +from .api_path_groups import ( + APIPathGroupsResource, + AsyncAPIPathGroupsResource, + APIPathGroupsResourceWithRawResponse, + AsyncAPIPathGroupsResourceWithRawResponse, + APIPathGroupsResourceWithStreamingResponse, + AsyncAPIPathGroupsResourceWithStreamingResponse, +) +from .insight_silences import ( + InsightSilencesResource, + AsyncInsightSilencesResource, + InsightSilencesResourceWithRawResponse, + AsyncInsightSilencesResourceWithRawResponse, + InsightSilencesResourceWithStreamingResponse, + AsyncInsightSilencesResourceWithStreamingResponse, +) + +__all__ = [ + "SettingsResource", + "AsyncSettingsResource", + "SettingsResourceWithRawResponse", + "AsyncSettingsResourceWithRawResponse", + "SettingsResourceWithStreamingResponse", + "AsyncSettingsResourceWithStreamingResponse", + "APIPathsResource", + "AsyncAPIPathsResource", + "APIPathsResourceWithRawResponse", + "AsyncAPIPathsResourceWithRawResponse", + "APIPathsResourceWithStreamingResponse", + "AsyncAPIPathsResourceWithStreamingResponse", + "APIPathGroupsResource", + "AsyncAPIPathGroupsResource", + "APIPathGroupsResourceWithRawResponse", + "AsyncAPIPathGroupsResourceWithRawResponse", + "APIPathGroupsResourceWithStreamingResponse", + "AsyncAPIPathGroupsResourceWithStreamingResponse", + "APIDiscoveryResource", + "AsyncAPIDiscoveryResource", + "APIDiscoveryResourceWithRawResponse", + "AsyncAPIDiscoveryResourceWithRawResponse", + "APIDiscoveryResourceWithStreamingResponse", + "AsyncAPIDiscoveryResourceWithStreamingResponse", + "InsightsResource", + "AsyncInsightsResource", + "InsightsResourceWithRawResponse", + "AsyncInsightsResourceWithRawResponse", + "InsightsResourceWithStreamingResponse", + "AsyncInsightsResourceWithStreamingResponse", + "InsightSilencesResource", + "AsyncInsightSilencesResource", + "InsightSilencesResourceWithRawResponse", + "AsyncInsightSilencesResourceWithRawResponse", + "InsightSilencesResourceWithStreamingResponse", + "AsyncInsightSilencesResourceWithStreamingResponse", + "StatisticsResource", + "AsyncStatisticsResource", + "StatisticsResourceWithRawResponse", + "AsyncStatisticsResourceWithRawResponse", + "StatisticsResourceWithStreamingResponse", + "AsyncStatisticsResourceWithStreamingResponse", + "CustomRulesResource", + "AsyncCustomRulesResource", + "CustomRulesResourceWithRawResponse", + "AsyncCustomRulesResourceWithRawResponse", + "CustomRulesResourceWithStreamingResponse", + "AsyncCustomRulesResourceWithStreamingResponse", + "FirewallRulesResource", + "AsyncFirewallRulesResource", + "FirewallRulesResourceWithRawResponse", + "AsyncFirewallRulesResourceWithRawResponse", + "FirewallRulesResourceWithStreamingResponse", + "AsyncFirewallRulesResourceWithStreamingResponse", + "AdvancedRulesResource", + "AsyncAdvancedRulesResource", + "AdvancedRulesResourceWithRawResponse", + "AsyncAdvancedRulesResourceWithRawResponse", + "AdvancedRulesResourceWithStreamingResponse", + "AsyncAdvancedRulesResourceWithStreamingResponse", + "DomainsResource", + "AsyncDomainsResource", + "DomainsResourceWithRawResponse", + "AsyncDomainsResourceWithRawResponse", + "DomainsResourceWithStreamingResponse", + "AsyncDomainsResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/waap/domains/advanced_rules.py b/src/gcore/resources/waap/domains/advanced_rules.py new file mode 100644 index 00000000..87e9e974 --- /dev/null +++ b/src/gcore/resources/waap/domains/advanced_rules.py @@ -0,0 +1,907 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.waap.domains import advanced_rule_list_params, advanced_rule_create_params, advanced_rule_update_params +from ....types.waap.domains.waap_advanced_rule import WaapAdvancedRule + +__all__ = ["AdvancedRulesResource", "AsyncAdvancedRulesResource"] + + +class AdvancedRulesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> AdvancedRulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AdvancedRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AdvancedRulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AdvancedRulesResourceWithStreamingResponse(self) + + def create( + self, + domain_id: int, + *, + action: advanced_rule_create_params.Action, + enabled: bool, + name: str, + source: str, + description: str | Omit = omit, + phase: Optional[Literal["access", "header_filter", "body_filter"]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAdvancedRule: + """ + Create an advanced rule + + Args: + domain_id: The domain ID + + action: The action that the rule takes when triggered. Only one action can be set per + rule. + + enabled: Whether or not the rule is enabled + + name: The name assigned to the rule + + source: A CEL syntax expression that contains the rule's conditions. Allowed objects + are: request, whois, session, response, tags, `user_defined_tags`, `user_agent`, + `client_data`. + + More info can be found here: + https://gcore.com/docs/waap/waap-rules/advanced-rules + + description: The description assigned to the rule + + phase: The WAAP request/response phase for applying the rule. Default is "access". + + The "access" phase is responsible for modifying the request before it is sent to + the origin server. + + The "header_filter" phase is responsible for modifying the HTTP headers of a + response before they are sent back to the client. + + The "body_filter" phase is responsible for modifying the body of a response + before it is sent back to the client. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/waap/v1/domains/{domain_id}/advanced-rules", + body=maybe_transform( + { + "action": action, + "enabled": enabled, + "name": name, + "source": source, + "description": description, + "phase": phase, + }, + advanced_rule_create_params.AdvancedRuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAdvancedRule, + ) + + def update( + self, + rule_id: int, + *, + domain_id: int, + action: Optional[advanced_rule_update_params.Action] | Omit = omit, + description: Optional[str] | Omit = omit, + enabled: Optional[bool] | Omit = omit, + name: Optional[str] | Omit = omit, + phase: Optional[Literal["access", "header_filter", "body_filter"]] | Omit = omit, + source: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Only properties present in the request will be updated + + Args: + domain_id: The domain ID + + rule_id: The advanced rule ID + + action: The action that a WAAP rule takes when triggered. + + description: The description assigned to the rule + + enabled: Whether or not the rule is enabled + + name: The name assigned to the rule + + phase: The WAAP request/response phase for applying the rule. + + The "access" phase is responsible for modifying the request before it is sent to + the origin server. + + The "header_filter" phase is responsible for modifying the HTTP headers of a + response before they are sent back to the client. + + The "body_filter" phase is responsible for modifying the body of a response + before it is sent back to the client. + + source: A CEL syntax expression that contains the rule's conditions. Allowed objects + are: request, whois, session, response, tags, `user_defined_tags`, `user_agent`, + `client_data`. + + More info can be found here: + https://gcore.com/docs/waap/waap-rules/advanced-rules + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._patch( + f"/waap/v1/domains/{domain_id}/advanced-rules/{rule_id}", + body=maybe_transform( + { + "action": action, + "description": description, + "enabled": enabled, + "name": name, + "phase": phase, + "source": source, + }, + advanced_rule_update_params.AdvancedRuleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + domain_id: int, + *, + action: Literal["allow", "block", "captcha", "handshake", "monitor", "tag"] | Omit = omit, + description: str | Omit = omit, + enabled: bool | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Optional[ + Literal[ + "id", + "name", + "description", + "enabled", + "action", + "phase", + "-id", + "-name", + "-description", + "-enabled", + "-action", + "-phase", + ] + ] + | Omit = omit, + phase: Literal["access", "header_filter", "body_filter"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapAdvancedRule]: + """ + Retrieve a list of advanced rules assigned to a domain, offering filter, + ordering, and pagination capabilities + + Args: + domain_id: The domain ID + + action: Filter to refine results by specific actions + + description: Filter rules based on their description. Supports '\\**' as a wildcard character. + + enabled: Filter rules based on their active status + + limit: Number of items to return + + name: Filter rules based on their name. Supports '\\**' as a wildcard character. + + offset: Number of items to skip + + ordering: Determine the field to order results by + + phase: Filter rules based on the WAAP request/response phase for applying the rule. + + The "access" phase is responsible for modifying the request before it is sent to + the origin server. + + The "header_filter" phase is responsible for modifying the HTTP headers of a + response before they are sent back to the client. + + The "body_filter" phase is responsible for modifying the body of a response + before it is sent back to the client. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/advanced-rules", + page=SyncOffsetPage[WaapAdvancedRule], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "action": action, + "description": description, + "enabled": enabled, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + "phase": phase, + }, + advanced_rule_list_params.AdvancedRuleListParams, + ), + ), + model=WaapAdvancedRule, + ) + + def delete( + self, + rule_id: int, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete an advanced rule + + Args: + domain_id: The domain ID + + rule_id: The advanced rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/waap/v1/domains/{domain_id}/advanced-rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + rule_id: int, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAdvancedRule: + """ + Retrieve a specific advanced rule assigned to a domain + + Args: + domain_id: The domain ID + + rule_id: The advanced rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/waap/v1/domains/{domain_id}/advanced-rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAdvancedRule, + ) + + def toggle( + self, + action: Literal["enable", "disable"], + *, + domain_id: int, + rule_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Toggle an advanced rule + + Args: + domain_id: The domain ID + + rule_id: The advanced rule ID + + action: Enable or disable an advanced rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not action: + raise ValueError(f"Expected a non-empty value for `action` but received {action!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._patch( + f"/waap/v1/domains/{domain_id}/advanced-rules/{rule_id}/{action}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncAdvancedRulesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAdvancedRulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncAdvancedRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAdvancedRulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncAdvancedRulesResourceWithStreamingResponse(self) + + async def create( + self, + domain_id: int, + *, + action: advanced_rule_create_params.Action, + enabled: bool, + name: str, + source: str, + description: str | Omit = omit, + phase: Optional[Literal["access", "header_filter", "body_filter"]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAdvancedRule: + """ + Create an advanced rule + + Args: + domain_id: The domain ID + + action: The action that the rule takes when triggered. Only one action can be set per + rule. + + enabled: Whether or not the rule is enabled + + name: The name assigned to the rule + + source: A CEL syntax expression that contains the rule's conditions. Allowed objects + are: request, whois, session, response, tags, `user_defined_tags`, `user_agent`, + `client_data`. + + More info can be found here: + https://gcore.com/docs/waap/waap-rules/advanced-rules + + description: The description assigned to the rule + + phase: The WAAP request/response phase for applying the rule. Default is "access". + + The "access" phase is responsible for modifying the request before it is sent to + the origin server. + + The "header_filter" phase is responsible for modifying the HTTP headers of a + response before they are sent back to the client. + + The "body_filter" phase is responsible for modifying the body of a response + before it is sent back to the client. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/waap/v1/domains/{domain_id}/advanced-rules", + body=await async_maybe_transform( + { + "action": action, + "enabled": enabled, + "name": name, + "source": source, + "description": description, + "phase": phase, + }, + advanced_rule_create_params.AdvancedRuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAdvancedRule, + ) + + async def update( + self, + rule_id: int, + *, + domain_id: int, + action: Optional[advanced_rule_update_params.Action] | Omit = omit, + description: Optional[str] | Omit = omit, + enabled: Optional[bool] | Omit = omit, + name: Optional[str] | Omit = omit, + phase: Optional[Literal["access", "header_filter", "body_filter"]] | Omit = omit, + source: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Only properties present in the request will be updated + + Args: + domain_id: The domain ID + + rule_id: The advanced rule ID + + action: The action that a WAAP rule takes when triggered. + + description: The description assigned to the rule + + enabled: Whether or not the rule is enabled + + name: The name assigned to the rule + + phase: The WAAP request/response phase for applying the rule. + + The "access" phase is responsible for modifying the request before it is sent to + the origin server. + + The "header_filter" phase is responsible for modifying the HTTP headers of a + response before they are sent back to the client. + + The "body_filter" phase is responsible for modifying the body of a response + before it is sent back to the client. + + source: A CEL syntax expression that contains the rule's conditions. Allowed objects + are: request, whois, session, response, tags, `user_defined_tags`, `user_agent`, + `client_data`. + + More info can be found here: + https://gcore.com/docs/waap/waap-rules/advanced-rules + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._patch( + f"/waap/v1/domains/{domain_id}/advanced-rules/{rule_id}", + body=await async_maybe_transform( + { + "action": action, + "description": description, + "enabled": enabled, + "name": name, + "phase": phase, + "source": source, + }, + advanced_rule_update_params.AdvancedRuleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + domain_id: int, + *, + action: Literal["allow", "block", "captcha", "handshake", "monitor", "tag"] | Omit = omit, + description: str | Omit = omit, + enabled: bool | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Optional[ + Literal[ + "id", + "name", + "description", + "enabled", + "action", + "phase", + "-id", + "-name", + "-description", + "-enabled", + "-action", + "-phase", + ] + ] + | Omit = omit, + phase: Literal["access", "header_filter", "body_filter"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapAdvancedRule, AsyncOffsetPage[WaapAdvancedRule]]: + """ + Retrieve a list of advanced rules assigned to a domain, offering filter, + ordering, and pagination capabilities + + Args: + domain_id: The domain ID + + action: Filter to refine results by specific actions + + description: Filter rules based on their description. Supports '\\**' as a wildcard character. + + enabled: Filter rules based on their active status + + limit: Number of items to return + + name: Filter rules based on their name. Supports '\\**' as a wildcard character. + + offset: Number of items to skip + + ordering: Determine the field to order results by + + phase: Filter rules based on the WAAP request/response phase for applying the rule. + + The "access" phase is responsible for modifying the request before it is sent to + the origin server. + + The "header_filter" phase is responsible for modifying the HTTP headers of a + response before they are sent back to the client. + + The "body_filter" phase is responsible for modifying the body of a response + before it is sent back to the client. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/advanced-rules", + page=AsyncOffsetPage[WaapAdvancedRule], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "action": action, + "description": description, + "enabled": enabled, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + "phase": phase, + }, + advanced_rule_list_params.AdvancedRuleListParams, + ), + ), + model=WaapAdvancedRule, + ) + + async def delete( + self, + rule_id: int, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete an advanced rule + + Args: + domain_id: The domain ID + + rule_id: The advanced rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/waap/v1/domains/{domain_id}/advanced-rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + rule_id: int, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAdvancedRule: + """ + Retrieve a specific advanced rule assigned to a domain + + Args: + domain_id: The domain ID + + rule_id: The advanced rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/waap/v1/domains/{domain_id}/advanced-rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAdvancedRule, + ) + + async def toggle( + self, + action: Literal["enable", "disable"], + *, + domain_id: int, + rule_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Toggle an advanced rule + + Args: + domain_id: The domain ID + + rule_id: The advanced rule ID + + action: Enable or disable an advanced rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not action: + raise ValueError(f"Expected a non-empty value for `action` but received {action!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._patch( + f"/waap/v1/domains/{domain_id}/advanced-rules/{rule_id}/{action}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AdvancedRulesResourceWithRawResponse: + def __init__(self, advanced_rules: AdvancedRulesResource) -> None: + self._advanced_rules = advanced_rules + + self.create = to_raw_response_wrapper( + advanced_rules.create, + ) + self.update = to_raw_response_wrapper( + advanced_rules.update, + ) + self.list = to_raw_response_wrapper( + advanced_rules.list, + ) + self.delete = to_raw_response_wrapper( + advanced_rules.delete, + ) + self.get = to_raw_response_wrapper( + advanced_rules.get, + ) + self.toggle = to_raw_response_wrapper( + advanced_rules.toggle, + ) + + +class AsyncAdvancedRulesResourceWithRawResponse: + def __init__(self, advanced_rules: AsyncAdvancedRulesResource) -> None: + self._advanced_rules = advanced_rules + + self.create = async_to_raw_response_wrapper( + advanced_rules.create, + ) + self.update = async_to_raw_response_wrapper( + advanced_rules.update, + ) + self.list = async_to_raw_response_wrapper( + advanced_rules.list, + ) + self.delete = async_to_raw_response_wrapper( + advanced_rules.delete, + ) + self.get = async_to_raw_response_wrapper( + advanced_rules.get, + ) + self.toggle = async_to_raw_response_wrapper( + advanced_rules.toggle, + ) + + +class AdvancedRulesResourceWithStreamingResponse: + def __init__(self, advanced_rules: AdvancedRulesResource) -> None: + self._advanced_rules = advanced_rules + + self.create = to_streamed_response_wrapper( + advanced_rules.create, + ) + self.update = to_streamed_response_wrapper( + advanced_rules.update, + ) + self.list = to_streamed_response_wrapper( + advanced_rules.list, + ) + self.delete = to_streamed_response_wrapper( + advanced_rules.delete, + ) + self.get = to_streamed_response_wrapper( + advanced_rules.get, + ) + self.toggle = to_streamed_response_wrapper( + advanced_rules.toggle, + ) + + +class AsyncAdvancedRulesResourceWithStreamingResponse: + def __init__(self, advanced_rules: AsyncAdvancedRulesResource) -> None: + self._advanced_rules = advanced_rules + + self.create = async_to_streamed_response_wrapper( + advanced_rules.create, + ) + self.update = async_to_streamed_response_wrapper( + advanced_rules.update, + ) + self.list = async_to_streamed_response_wrapper( + advanced_rules.list, + ) + self.delete = async_to_streamed_response_wrapper( + advanced_rules.delete, + ) + self.get = async_to_streamed_response_wrapper( + advanced_rules.get, + ) + self.toggle = async_to_streamed_response_wrapper( + advanced_rules.toggle, + ) diff --git a/src/gcore/resources/waap/domains/api_discovery.py b/src/gcore/resources/waap/domains/api_discovery.py new file mode 100644 index 00000000..f83862da --- /dev/null +++ b/src/gcore/resources/waap/domains/api_discovery.py @@ -0,0 +1,763 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.waap.domains import ( + api_discovery_upload_openapi_params, + api_discovery_update_settings_params, + api_discovery_list_scan_results_params, +) +from ....types.waap.domains.waap_task_id import WaapTaskID +from ....types.waap.domains.waap_api_scan_result import WaapAPIScanResult +from ....types.waap.domains.waap_api_discovery_settings import WaapAPIDiscoverySettings + +__all__ = ["APIDiscoveryResource", "AsyncAPIDiscoveryResource"] + + +class APIDiscoveryResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> APIDiscoveryResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return APIDiscoveryResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> APIDiscoveryResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return APIDiscoveryResourceWithStreamingResponse(self) + + def get_scan_result( + self, + scan_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAPIScanResult: + """ + Get Scan Result + + Args: + domain_id: The domain ID + + scan_id: The scan ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not scan_id: + raise ValueError(f"Expected a non-empty value for `scan_id` but received {scan_id!r}") + return self._get( + f"/waap/v1/domains/{domain_id}/api-discovery/scan-results/{scan_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAPIScanResult, + ) + + def get_settings( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAPIDiscoverySettings: + """ + Retrieve the API discovery settings for a domain + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/waap/v1/domains/{domain_id}/api-discovery/settings", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAPIDiscoverySettings, + ) + + def list_scan_results( + self, + domain_id: int, + *, + limit: int | Omit = omit, + message: Optional[str] | Omit = omit, + offset: int | Omit = omit, + ordering: Literal[ + "id", + "type", + "start_time", + "end_time", + "status", + "message", + "-id", + "-type", + "-start_time", + "-end_time", + "-status", + "-message", + ] + | Omit = omit, + status: Optional[Literal["SUCCESS", "FAILURE", "IN_PROGRESS"]] | Omit = omit, + type: Optional[Literal["TRAFFIC_SCAN", "API_DESCRIPTION_FILE_SCAN"]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapAPIScanResult]: + """ + Get Scan Results + + Args: + domain_id: The domain ID + + limit: Number of items to return + + message: Filter by the message of the scan. Supports '\\**' as a wildcard character + + offset: Number of items to skip + + ordering: Sort the response by given field. + + status: Filter by the status of the scan + + type: Filter by the path of the scan type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/api-discovery/scan-results", + page=SyncOffsetPage[WaapAPIScanResult], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "message": message, + "offset": offset, + "ordering": ordering, + "status": status, + "type": type, + }, + api_discovery_list_scan_results_params.APIDiscoveryListScanResultsParams, + ), + ), + model=WaapAPIScanResult, + ) + + def scan_openapi( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapTaskID: + """Scan an API description file hosted online. + + The file must be in YAML or JSON + format and adhere to the OpenAPI specification. The location of the API + description file should be specified in the API discovery settings. + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/waap/v1/domains/{domain_id}/api-discovery/scan", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapTaskID, + ) + + def update_settings( + self, + domain_id: int, + *, + description_file_location: Optional[str] | Omit = omit, + description_file_scan_enabled: Optional[bool] | Omit = omit, + description_file_scan_interval_hours: Optional[int] | Omit = omit, + traffic_scan_enabled: Optional[bool] | Omit = omit, + traffic_scan_interval_hours: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAPIDiscoverySettings: + """ + Update the API discovery settings for a domain + + Args: + domain_id: The domain ID + + description_file_location: The URL of the API description file. This will be periodically scanned if + `descriptionFileScanEnabled` is enabled. Supported formats are YAML and JSON, + and it must adhere to OpenAPI versions 2, 3, or 3.1. + + description_file_scan_enabled: Indicates if periodic scan of the description file is enabled + + description_file_scan_interval_hours: The interval in hours for scanning the description file + + traffic_scan_enabled: Indicates if traffic scan is enabled + + traffic_scan_interval_hours: The interval in hours for scanning the traffic + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._patch( + f"/waap/v1/domains/{domain_id}/api-discovery/settings", + body=maybe_transform( + { + "description_file_location": description_file_location, + "description_file_scan_enabled": description_file_scan_enabled, + "description_file_scan_interval_hours": description_file_scan_interval_hours, + "traffic_scan_enabled": traffic_scan_enabled, + "traffic_scan_interval_hours": traffic_scan_interval_hours, + }, + api_discovery_update_settings_params.APIDiscoveryUpdateSettingsParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAPIDiscoverySettings, + ) + + def upload_openapi( + self, + domain_id: int, + *, + file_data: str, + file_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapTaskID: + """ + An API description file must adhere to the OpenAPI specification and be written + in YAML or JSON format. The file name should be provided as the value for the + `file_name` parameter. The contents of the file must be base64 encoded and + supplied as the value for the `file_data` parameter. + + Args: + domain_id: The domain ID + + file_data: Base64 representation of the description file. Supported formats are YAML and + JSON, and it must adhere to OpenAPI versions 2, 3, or 3.1. + + file_name: The name of the file + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/waap/v1/domains/{domain_id}/api-discovery/upload", + body=maybe_transform( + { + "file_data": file_data, + "file_name": file_name, + }, + api_discovery_upload_openapi_params.APIDiscoveryUploadOpenAPIParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapTaskID, + ) + + +class AsyncAPIDiscoveryResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAPIDiscoveryResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncAPIDiscoveryResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAPIDiscoveryResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncAPIDiscoveryResourceWithStreamingResponse(self) + + async def get_scan_result( + self, + scan_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAPIScanResult: + """ + Get Scan Result + + Args: + domain_id: The domain ID + + scan_id: The scan ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not scan_id: + raise ValueError(f"Expected a non-empty value for `scan_id` but received {scan_id!r}") + return await self._get( + f"/waap/v1/domains/{domain_id}/api-discovery/scan-results/{scan_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAPIScanResult, + ) + + async def get_settings( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAPIDiscoverySettings: + """ + Retrieve the API discovery settings for a domain + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/waap/v1/domains/{domain_id}/api-discovery/settings", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAPIDiscoverySettings, + ) + + def list_scan_results( + self, + domain_id: int, + *, + limit: int | Omit = omit, + message: Optional[str] | Omit = omit, + offset: int | Omit = omit, + ordering: Literal[ + "id", + "type", + "start_time", + "end_time", + "status", + "message", + "-id", + "-type", + "-start_time", + "-end_time", + "-status", + "-message", + ] + | Omit = omit, + status: Optional[Literal["SUCCESS", "FAILURE", "IN_PROGRESS"]] | Omit = omit, + type: Optional[Literal["TRAFFIC_SCAN", "API_DESCRIPTION_FILE_SCAN"]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapAPIScanResult, AsyncOffsetPage[WaapAPIScanResult]]: + """ + Get Scan Results + + Args: + domain_id: The domain ID + + limit: Number of items to return + + message: Filter by the message of the scan. Supports '\\**' as a wildcard character + + offset: Number of items to skip + + ordering: Sort the response by given field. + + status: Filter by the status of the scan + + type: Filter by the path of the scan type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/api-discovery/scan-results", + page=AsyncOffsetPage[WaapAPIScanResult], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "message": message, + "offset": offset, + "ordering": ordering, + "status": status, + "type": type, + }, + api_discovery_list_scan_results_params.APIDiscoveryListScanResultsParams, + ), + ), + model=WaapAPIScanResult, + ) + + async def scan_openapi( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapTaskID: + """Scan an API description file hosted online. + + The file must be in YAML or JSON + format and adhere to the OpenAPI specification. The location of the API + description file should be specified in the API discovery settings. + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/waap/v1/domains/{domain_id}/api-discovery/scan", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapTaskID, + ) + + async def update_settings( + self, + domain_id: int, + *, + description_file_location: Optional[str] | Omit = omit, + description_file_scan_enabled: Optional[bool] | Omit = omit, + description_file_scan_interval_hours: Optional[int] | Omit = omit, + traffic_scan_enabled: Optional[bool] | Omit = omit, + traffic_scan_interval_hours: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAPIDiscoverySettings: + """ + Update the API discovery settings for a domain + + Args: + domain_id: The domain ID + + description_file_location: The URL of the API description file. This will be periodically scanned if + `descriptionFileScanEnabled` is enabled. Supported formats are YAML and JSON, + and it must adhere to OpenAPI versions 2, 3, or 3.1. + + description_file_scan_enabled: Indicates if periodic scan of the description file is enabled + + description_file_scan_interval_hours: The interval in hours for scanning the description file + + traffic_scan_enabled: Indicates if traffic scan is enabled + + traffic_scan_interval_hours: The interval in hours for scanning the traffic + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._patch( + f"/waap/v1/domains/{domain_id}/api-discovery/settings", + body=await async_maybe_transform( + { + "description_file_location": description_file_location, + "description_file_scan_enabled": description_file_scan_enabled, + "description_file_scan_interval_hours": description_file_scan_interval_hours, + "traffic_scan_enabled": traffic_scan_enabled, + "traffic_scan_interval_hours": traffic_scan_interval_hours, + }, + api_discovery_update_settings_params.APIDiscoveryUpdateSettingsParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAPIDiscoverySettings, + ) + + async def upload_openapi( + self, + domain_id: int, + *, + file_data: str, + file_name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapTaskID: + """ + An API description file must adhere to the OpenAPI specification and be written + in YAML or JSON format. The file name should be provided as the value for the + `file_name` parameter. The contents of the file must be base64 encoded and + supplied as the value for the `file_data` parameter. + + Args: + domain_id: The domain ID + + file_data: Base64 representation of the description file. Supported formats are YAML and + JSON, and it must adhere to OpenAPI versions 2, 3, or 3.1. + + file_name: The name of the file + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/waap/v1/domains/{domain_id}/api-discovery/upload", + body=await async_maybe_transform( + { + "file_data": file_data, + "file_name": file_name, + }, + api_discovery_upload_openapi_params.APIDiscoveryUploadOpenAPIParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapTaskID, + ) + + +class APIDiscoveryResourceWithRawResponse: + def __init__(self, api_discovery: APIDiscoveryResource) -> None: + self._api_discovery = api_discovery + + self.get_scan_result = to_raw_response_wrapper( + api_discovery.get_scan_result, + ) + self.get_settings = to_raw_response_wrapper( + api_discovery.get_settings, + ) + self.list_scan_results = to_raw_response_wrapper( + api_discovery.list_scan_results, + ) + self.scan_openapi = to_raw_response_wrapper( + api_discovery.scan_openapi, + ) + self.update_settings = to_raw_response_wrapper( + api_discovery.update_settings, + ) + self.upload_openapi = to_raw_response_wrapper( + api_discovery.upload_openapi, + ) + + +class AsyncAPIDiscoveryResourceWithRawResponse: + def __init__(self, api_discovery: AsyncAPIDiscoveryResource) -> None: + self._api_discovery = api_discovery + + self.get_scan_result = async_to_raw_response_wrapper( + api_discovery.get_scan_result, + ) + self.get_settings = async_to_raw_response_wrapper( + api_discovery.get_settings, + ) + self.list_scan_results = async_to_raw_response_wrapper( + api_discovery.list_scan_results, + ) + self.scan_openapi = async_to_raw_response_wrapper( + api_discovery.scan_openapi, + ) + self.update_settings = async_to_raw_response_wrapper( + api_discovery.update_settings, + ) + self.upload_openapi = async_to_raw_response_wrapper( + api_discovery.upload_openapi, + ) + + +class APIDiscoveryResourceWithStreamingResponse: + def __init__(self, api_discovery: APIDiscoveryResource) -> None: + self._api_discovery = api_discovery + + self.get_scan_result = to_streamed_response_wrapper( + api_discovery.get_scan_result, + ) + self.get_settings = to_streamed_response_wrapper( + api_discovery.get_settings, + ) + self.list_scan_results = to_streamed_response_wrapper( + api_discovery.list_scan_results, + ) + self.scan_openapi = to_streamed_response_wrapper( + api_discovery.scan_openapi, + ) + self.update_settings = to_streamed_response_wrapper( + api_discovery.update_settings, + ) + self.upload_openapi = to_streamed_response_wrapper( + api_discovery.upload_openapi, + ) + + +class AsyncAPIDiscoveryResourceWithStreamingResponse: + def __init__(self, api_discovery: AsyncAPIDiscoveryResource) -> None: + self._api_discovery = api_discovery + + self.get_scan_result = async_to_streamed_response_wrapper( + api_discovery.get_scan_result, + ) + self.get_settings = async_to_streamed_response_wrapper( + api_discovery.get_settings, + ) + self.list_scan_results = async_to_streamed_response_wrapper( + api_discovery.list_scan_results, + ) + self.scan_openapi = async_to_streamed_response_wrapper( + api_discovery.scan_openapi, + ) + self.update_settings = async_to_streamed_response_wrapper( + api_discovery.update_settings, + ) + self.upload_openapi = async_to_streamed_response_wrapper( + api_discovery.upload_openapi, + ) diff --git a/src/gcore/resources/waap/domains/api_path_groups.py b/src/gcore/resources/waap/domains/api_path_groups.py new file mode 100644 index 00000000..a6b25b2e --- /dev/null +++ b/src/gcore/resources/waap/domains/api_path_groups.py @@ -0,0 +1,163 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.waap.domains.api_path_group_list import APIPathGroupList + +__all__ = ["APIPathGroupsResource", "AsyncAPIPathGroupsResource"] + + +class APIPathGroupsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> APIPathGroupsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return APIPathGroupsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> APIPathGroupsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return APIPathGroupsResourceWithStreamingResponse(self) + + def list( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> APIPathGroupList: + """ + Retrieve a list of API path groups for a specific domain + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/waap/v1/domains/{domain_id}/api-path-groups", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=APIPathGroupList, + ) + + +class AsyncAPIPathGroupsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAPIPathGroupsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncAPIPathGroupsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAPIPathGroupsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncAPIPathGroupsResourceWithStreamingResponse(self) + + async def list( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> APIPathGroupList: + """ + Retrieve a list of API path groups for a specific domain + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/waap/v1/domains/{domain_id}/api-path-groups", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=APIPathGroupList, + ) + + +class APIPathGroupsResourceWithRawResponse: + def __init__(self, api_path_groups: APIPathGroupsResource) -> None: + self._api_path_groups = api_path_groups + + self.list = to_raw_response_wrapper( + api_path_groups.list, + ) + + +class AsyncAPIPathGroupsResourceWithRawResponse: + def __init__(self, api_path_groups: AsyncAPIPathGroupsResource) -> None: + self._api_path_groups = api_path_groups + + self.list = async_to_raw_response_wrapper( + api_path_groups.list, + ) + + +class APIPathGroupsResourceWithStreamingResponse: + def __init__(self, api_path_groups: APIPathGroupsResource) -> None: + self._api_path_groups = api_path_groups + + self.list = to_streamed_response_wrapper( + api_path_groups.list, + ) + + +class AsyncAPIPathGroupsResourceWithStreamingResponse: + def __init__(self, api_path_groups: AsyncAPIPathGroupsResource) -> None: + self._api_path_groups = api_path_groups + + self.list = async_to_streamed_response_wrapper( + api_path_groups.list, + ) diff --git a/src/gcore/resources/waap/domains/api_paths.py b/src/gcore/resources/waap/domains/api_paths.py new file mode 100644 index 00000000..cdc33365 --- /dev/null +++ b/src/gcore/resources/waap/domains/api_paths.py @@ -0,0 +1,745 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.waap.domains import api_path_list_params, api_path_create_params, api_path_update_params +from ....types.waap.domains.waap_api_path import WaapAPIPath + +__all__ = ["APIPathsResource", "AsyncAPIPathsResource"] + + +class APIPathsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> APIPathsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return APIPathsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> APIPathsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return APIPathsResourceWithStreamingResponse(self) + + def create( + self, + domain_id: int, + *, + http_scheme: Literal["HTTP", "HTTPS"], + method: Literal["GET", "POST", "PUT", "PATCH", "DELETE", "TRACE", "HEAD", "OPTIONS"], + path: str, + api_groups: SequenceNotStr[str] | Omit = omit, + api_version: str | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAPIPath: + """ + Create an API path for a domain + + Args: + domain_id: The domain ID + + http_scheme: The different HTTP schemes an API path can have + + method: The different methods an API path can have + + path: The API path, locations that are saved for resource IDs will be put in curly + brackets + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/waap/v1/domains/{domain_id}/api-paths", + body=maybe_transform( + { + "http_scheme": http_scheme, + "method": method, + "path": path, + "api_groups": api_groups, + "api_version": api_version, + "tags": tags, + }, + api_path_create_params.APIPathCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAPIPath, + ) + + def update( + self, + path_id: str, + *, + domain_id: int, + api_groups: SequenceNotStr[str] | Omit = omit, + path: str | Omit = omit, + status: Literal["CONFIRMED_API", "POTENTIAL_API", "NOT_API", "DELISTED_API"] | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Update a specific API path for a domain + + Args: + domain_id: The domain ID + + path_id: The path ID + + path: The updated API path. When updating the path, variables can be renamed, path + parts can be converted to variables and vice versa. + + status: The different statuses an API path can have + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not path_id: + raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._patch( + f"/waap/v1/domains/{domain_id}/api-paths/{path_id}", + body=maybe_transform( + { + "api_groups": api_groups, + "path": path, + "status": status, + "tags": tags, + }, + api_path_update_params.APIPathUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + domain_id: int, + *, + api_group: Optional[str] | Omit = omit, + api_version: Optional[str] | Omit = omit, + http_scheme: Optional[Literal["HTTP", "HTTPS"]] | Omit = omit, + ids: Optional[SequenceNotStr[str]] | Omit = omit, + limit: int | Omit = omit, + method: Optional[Literal["GET", "POST", "PUT", "PATCH", "DELETE", "TRACE", "HEAD", "OPTIONS"]] | Omit = omit, + offset: int | Omit = omit, + ordering: Literal[ + "id", + "path", + "method", + "api_version", + "http_scheme", + "first_detected", + "last_detected", + "status", + "source", + "-id", + "-path", + "-method", + "-api_version", + "-http_scheme", + "-first_detected", + "-last_detected", + "-status", + "-source", + ] + | Omit = omit, + path: Optional[str] | Omit = omit, + source: Optional[Literal["API_DESCRIPTION_FILE", "TRAFFIC_SCAN", "USER_DEFINED"]] | Omit = omit, + status: Optional[List[Literal["CONFIRMED_API", "POTENTIAL_API", "NOT_API", "DELISTED_API"]]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapAPIPath]: + """ + Retrieve a list of API paths for a specific domain + + Args: + domain_id: The domain ID + + api_group: Filter by the API group associated with the API path + + api_version: Filter by the API version + + http_scheme: Filter by the HTTP version of the API path + + ids: Filter by the path ID + + limit: Number of items to return + + method: Filter by the API RESTful method + + offset: Number of items to skip + + ordering: Sort the response by given field. + + path: Filter by the path. Supports '\\**' as a wildcard character + + source: Filter by the source of the discovered API + + status: Filter by the status of the discovered API path + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/api-paths", + page=SyncOffsetPage[WaapAPIPath], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "api_group": api_group, + "api_version": api_version, + "http_scheme": http_scheme, + "ids": ids, + "limit": limit, + "method": method, + "offset": offset, + "ordering": ordering, + "path": path, + "source": source, + "status": status, + }, + api_path_list_params.APIPathListParams, + ), + ), + model=WaapAPIPath, + ) + + def delete( + self, + path_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific API path for a domain + + Args: + domain_id: The domain ID + + path_id: The path ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not path_id: + raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/waap/v1/domains/{domain_id}/api-paths/{path_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + path_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAPIPath: + """ + Retrieve a specific API path for a domain + + Args: + domain_id: The domain ID + + path_id: The path ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not path_id: + raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}") + return self._get( + f"/waap/v1/domains/{domain_id}/api-paths/{path_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAPIPath, + ) + + +class AsyncAPIPathsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAPIPathsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncAPIPathsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAPIPathsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncAPIPathsResourceWithStreamingResponse(self) + + async def create( + self, + domain_id: int, + *, + http_scheme: Literal["HTTP", "HTTPS"], + method: Literal["GET", "POST", "PUT", "PATCH", "DELETE", "TRACE", "HEAD", "OPTIONS"], + path: str, + api_groups: SequenceNotStr[str] | Omit = omit, + api_version: str | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAPIPath: + """ + Create an API path for a domain + + Args: + domain_id: The domain ID + + http_scheme: The different HTTP schemes an API path can have + + method: The different methods an API path can have + + path: The API path, locations that are saved for resource IDs will be put in curly + brackets + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/waap/v1/domains/{domain_id}/api-paths", + body=await async_maybe_transform( + { + "http_scheme": http_scheme, + "method": method, + "path": path, + "api_groups": api_groups, + "api_version": api_version, + "tags": tags, + }, + api_path_create_params.APIPathCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAPIPath, + ) + + async def update( + self, + path_id: str, + *, + domain_id: int, + api_groups: SequenceNotStr[str] | Omit = omit, + path: str | Omit = omit, + status: Literal["CONFIRMED_API", "POTENTIAL_API", "NOT_API", "DELISTED_API"] | Omit = omit, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Update a specific API path for a domain + + Args: + domain_id: The domain ID + + path_id: The path ID + + path: The updated API path. When updating the path, variables can be renamed, path + parts can be converted to variables and vice versa. + + status: The different statuses an API path can have + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not path_id: + raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._patch( + f"/waap/v1/domains/{domain_id}/api-paths/{path_id}", + body=await async_maybe_transform( + { + "api_groups": api_groups, + "path": path, + "status": status, + "tags": tags, + }, + api_path_update_params.APIPathUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + domain_id: int, + *, + api_group: Optional[str] | Omit = omit, + api_version: Optional[str] | Omit = omit, + http_scheme: Optional[Literal["HTTP", "HTTPS"]] | Omit = omit, + ids: Optional[SequenceNotStr[str]] | Omit = omit, + limit: int | Omit = omit, + method: Optional[Literal["GET", "POST", "PUT", "PATCH", "DELETE", "TRACE", "HEAD", "OPTIONS"]] | Omit = omit, + offset: int | Omit = omit, + ordering: Literal[ + "id", + "path", + "method", + "api_version", + "http_scheme", + "first_detected", + "last_detected", + "status", + "source", + "-id", + "-path", + "-method", + "-api_version", + "-http_scheme", + "-first_detected", + "-last_detected", + "-status", + "-source", + ] + | Omit = omit, + path: Optional[str] | Omit = omit, + source: Optional[Literal["API_DESCRIPTION_FILE", "TRAFFIC_SCAN", "USER_DEFINED"]] | Omit = omit, + status: Optional[List[Literal["CONFIRMED_API", "POTENTIAL_API", "NOT_API", "DELISTED_API"]]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapAPIPath, AsyncOffsetPage[WaapAPIPath]]: + """ + Retrieve a list of API paths for a specific domain + + Args: + domain_id: The domain ID + + api_group: Filter by the API group associated with the API path + + api_version: Filter by the API version + + http_scheme: Filter by the HTTP version of the API path + + ids: Filter by the path ID + + limit: Number of items to return + + method: Filter by the API RESTful method + + offset: Number of items to skip + + ordering: Sort the response by given field. + + path: Filter by the path. Supports '\\**' as a wildcard character + + source: Filter by the source of the discovered API + + status: Filter by the status of the discovered API path + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/api-paths", + page=AsyncOffsetPage[WaapAPIPath], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "api_group": api_group, + "api_version": api_version, + "http_scheme": http_scheme, + "ids": ids, + "limit": limit, + "method": method, + "offset": offset, + "ordering": ordering, + "path": path, + "source": source, + "status": status, + }, + api_path_list_params.APIPathListParams, + ), + ), + model=WaapAPIPath, + ) + + async def delete( + self, + path_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a specific API path for a domain + + Args: + domain_id: The domain ID + + path_id: The path ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not path_id: + raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/waap/v1/domains/{domain_id}/api-paths/{path_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + path_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapAPIPath: + """ + Retrieve a specific API path for a domain + + Args: + domain_id: The domain ID + + path_id: The path ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not path_id: + raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}") + return await self._get( + f"/waap/v1/domains/{domain_id}/api-paths/{path_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapAPIPath, + ) + + +class APIPathsResourceWithRawResponse: + def __init__(self, api_paths: APIPathsResource) -> None: + self._api_paths = api_paths + + self.create = to_raw_response_wrapper( + api_paths.create, + ) + self.update = to_raw_response_wrapper( + api_paths.update, + ) + self.list = to_raw_response_wrapper( + api_paths.list, + ) + self.delete = to_raw_response_wrapper( + api_paths.delete, + ) + self.get = to_raw_response_wrapper( + api_paths.get, + ) + + +class AsyncAPIPathsResourceWithRawResponse: + def __init__(self, api_paths: AsyncAPIPathsResource) -> None: + self._api_paths = api_paths + + self.create = async_to_raw_response_wrapper( + api_paths.create, + ) + self.update = async_to_raw_response_wrapper( + api_paths.update, + ) + self.list = async_to_raw_response_wrapper( + api_paths.list, + ) + self.delete = async_to_raw_response_wrapper( + api_paths.delete, + ) + self.get = async_to_raw_response_wrapper( + api_paths.get, + ) + + +class APIPathsResourceWithStreamingResponse: + def __init__(self, api_paths: APIPathsResource) -> None: + self._api_paths = api_paths + + self.create = to_streamed_response_wrapper( + api_paths.create, + ) + self.update = to_streamed_response_wrapper( + api_paths.update, + ) + self.list = to_streamed_response_wrapper( + api_paths.list, + ) + self.delete = to_streamed_response_wrapper( + api_paths.delete, + ) + self.get = to_streamed_response_wrapper( + api_paths.get, + ) + + +class AsyncAPIPathsResourceWithStreamingResponse: + def __init__(self, api_paths: AsyncAPIPathsResource) -> None: + self._api_paths = api_paths + + self.create = async_to_streamed_response_wrapper( + api_paths.create, + ) + self.update = async_to_streamed_response_wrapper( + api_paths.update, + ) + self.list = async_to_streamed_response_wrapper( + api_paths.list, + ) + self.delete = async_to_streamed_response_wrapper( + api_paths.delete, + ) + self.get = async_to_streamed_response_wrapper( + api_paths.get, + ) diff --git a/src/gcore/resources/waap/domains/custom_rules.py b/src/gcore/resources/waap/domains/custom_rules.py new file mode 100644 index 00000000..e81e575e --- /dev/null +++ b/src/gcore/resources/waap/domains/custom_rules.py @@ -0,0 +1,888 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.waap.domains import ( + custom_rule_list_params, + custom_rule_create_params, + custom_rule_update_params, + custom_rule_delete_multiple_params, +) +from ....types.waap.domains.waap_custom_rule import WaapCustomRule + +__all__ = ["CustomRulesResource", "AsyncCustomRulesResource"] + + +class CustomRulesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CustomRulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return CustomRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CustomRulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return CustomRulesResourceWithStreamingResponse(self) + + def create( + self, + domain_id: int, + *, + action: custom_rule_create_params.Action, + conditions: Iterable[custom_rule_create_params.Condition], + enabled: bool, + name: str, + description: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapCustomRule: + """ + Create a custom rule + + Args: + domain_id: The domain ID + + action: The action that the rule takes when triggered. Only one action can be set per + rule. + + conditions: The conditions required for the WAAP engine to trigger the rule. Rules may have + between 1 and 5 conditions. All conditions must pass for the rule to trigger + + enabled: Whether or not the rule is enabled + + name: The name assigned to the rule + + description: The description assigned to the rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/waap/v1/domains/{domain_id}/custom-rules", + body=maybe_transform( + { + "action": action, + "conditions": conditions, + "enabled": enabled, + "name": name, + "description": description, + }, + custom_rule_create_params.CustomRuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapCustomRule, + ) + + def update( + self, + rule_id: int, + *, + domain_id: int, + action: Optional[custom_rule_update_params.Action] | Omit = omit, + conditions: Optional[Iterable[custom_rule_update_params.Condition]] | Omit = omit, + description: Optional[str] | Omit = omit, + enabled: Optional[bool] | Omit = omit, + name: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Only properties present in the request will be updated + + Args: + domain_id: The domain ID + + rule_id: The custom rule ID + + action: The action that a WAAP rule takes when triggered. + + conditions: The conditions required for the WAAP engine to trigger the rule. Rules may have + between 1 and 5 conditions. All conditions must pass for the rule to trigger + + description: The description assigned to the rule + + enabled: Whether or not the rule is enabled + + name: The name assigned to the rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._patch( + f"/waap/v1/domains/{domain_id}/custom-rules/{rule_id}", + body=maybe_transform( + { + "action": action, + "conditions": conditions, + "description": description, + "enabled": enabled, + "name": name, + }, + custom_rule_update_params.CustomRuleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + domain_id: int, + *, + action: Literal["allow", "block", "captcha", "handshake", "monitor", "tag"] | Omit = omit, + description: str | Omit = omit, + enabled: bool | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Optional[ + Literal[ + "id", "name", "description", "enabled", "action", "-id", "-name", "-description", "-enabled", "-action" + ] + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapCustomRule]: + """ + Extracts a list of custom rules assigned to a domain, offering filter, ordering, + and pagination capabilities + + Args: + domain_id: The domain ID + + action: Filter to refine results by specific actions + + description: Filter rules based on their description. Supports '\\**' as a wildcard character. + + enabled: Filter rules based on their active status + + limit: Number of items to return + + name: Filter rules based on their name. Supports '\\**' as a wildcard character. + + offset: Number of items to skip + + ordering: Determine the field to order results by + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/custom-rules", + page=SyncOffsetPage[WaapCustomRule], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "action": action, + "description": description, + "enabled": enabled, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + }, + custom_rule_list_params.CustomRuleListParams, + ), + ), + model=WaapCustomRule, + ) + + def delete( + self, + rule_id: int, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a custom rule + + Args: + domain_id: The domain ID + + rule_id: The custom rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/waap/v1/domains/{domain_id}/custom-rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def delete_multiple( + self, + domain_id: int, + *, + rule_ids: Iterable[int], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete multiple WAAP rules + + Args: + domain_id: The domain ID + + rule_ids: The IDs of the rules to delete + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/waap/v1/domains/{domain_id}/custom-rules/bulk_delete", + body=maybe_transform( + {"rule_ids": rule_ids}, custom_rule_delete_multiple_params.CustomRuleDeleteMultipleParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + rule_id: int, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapCustomRule: + """ + Extracts a specific custom rule assigned to a domain + + Args: + domain_id: The domain ID + + rule_id: The custom rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/waap/v1/domains/{domain_id}/custom-rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapCustomRule, + ) + + def toggle( + self, + action: Literal["enable", "disable"], + *, + domain_id: int, + rule_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Toggle a custom rule + + Args: + domain_id: The domain ID + + rule_id: The custom rule ID + + action: Enable or disable a custom rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not action: + raise ValueError(f"Expected a non-empty value for `action` but received {action!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._patch( + f"/waap/v1/domains/{domain_id}/custom-rules/{rule_id}/{action}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncCustomRulesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCustomRulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncCustomRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCustomRulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncCustomRulesResourceWithStreamingResponse(self) + + async def create( + self, + domain_id: int, + *, + action: custom_rule_create_params.Action, + conditions: Iterable[custom_rule_create_params.Condition], + enabled: bool, + name: str, + description: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapCustomRule: + """ + Create a custom rule + + Args: + domain_id: The domain ID + + action: The action that the rule takes when triggered. Only one action can be set per + rule. + + conditions: The conditions required for the WAAP engine to trigger the rule. Rules may have + between 1 and 5 conditions. All conditions must pass for the rule to trigger + + enabled: Whether or not the rule is enabled + + name: The name assigned to the rule + + description: The description assigned to the rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/waap/v1/domains/{domain_id}/custom-rules", + body=await async_maybe_transform( + { + "action": action, + "conditions": conditions, + "enabled": enabled, + "name": name, + "description": description, + }, + custom_rule_create_params.CustomRuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapCustomRule, + ) + + async def update( + self, + rule_id: int, + *, + domain_id: int, + action: Optional[custom_rule_update_params.Action] | Omit = omit, + conditions: Optional[Iterable[custom_rule_update_params.Condition]] | Omit = omit, + description: Optional[str] | Omit = omit, + enabled: Optional[bool] | Omit = omit, + name: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Only properties present in the request will be updated + + Args: + domain_id: The domain ID + + rule_id: The custom rule ID + + action: The action that a WAAP rule takes when triggered. + + conditions: The conditions required for the WAAP engine to trigger the rule. Rules may have + between 1 and 5 conditions. All conditions must pass for the rule to trigger + + description: The description assigned to the rule + + enabled: Whether or not the rule is enabled + + name: The name assigned to the rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._patch( + f"/waap/v1/domains/{domain_id}/custom-rules/{rule_id}", + body=await async_maybe_transform( + { + "action": action, + "conditions": conditions, + "description": description, + "enabled": enabled, + "name": name, + }, + custom_rule_update_params.CustomRuleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + domain_id: int, + *, + action: Literal["allow", "block", "captcha", "handshake", "monitor", "tag"] | Omit = omit, + description: str | Omit = omit, + enabled: bool | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Optional[ + Literal[ + "id", "name", "description", "enabled", "action", "-id", "-name", "-description", "-enabled", "-action" + ] + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapCustomRule, AsyncOffsetPage[WaapCustomRule]]: + """ + Extracts a list of custom rules assigned to a domain, offering filter, ordering, + and pagination capabilities + + Args: + domain_id: The domain ID + + action: Filter to refine results by specific actions + + description: Filter rules based on their description. Supports '\\**' as a wildcard character. + + enabled: Filter rules based on their active status + + limit: Number of items to return + + name: Filter rules based on their name. Supports '\\**' as a wildcard character. + + offset: Number of items to skip + + ordering: Determine the field to order results by + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/custom-rules", + page=AsyncOffsetPage[WaapCustomRule], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "action": action, + "description": description, + "enabled": enabled, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + }, + custom_rule_list_params.CustomRuleListParams, + ), + ), + model=WaapCustomRule, + ) + + async def delete( + self, + rule_id: int, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a custom rule + + Args: + domain_id: The domain ID + + rule_id: The custom rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/waap/v1/domains/{domain_id}/custom-rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def delete_multiple( + self, + domain_id: int, + *, + rule_ids: Iterable[int], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete multiple WAAP rules + + Args: + domain_id: The domain ID + + rule_ids: The IDs of the rules to delete + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/waap/v1/domains/{domain_id}/custom-rules/bulk_delete", + body=await async_maybe_transform( + {"rule_ids": rule_ids}, custom_rule_delete_multiple_params.CustomRuleDeleteMultipleParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + rule_id: int, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapCustomRule: + """ + Extracts a specific custom rule assigned to a domain + + Args: + domain_id: The domain ID + + rule_id: The custom rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/waap/v1/domains/{domain_id}/custom-rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapCustomRule, + ) + + async def toggle( + self, + action: Literal["enable", "disable"], + *, + domain_id: int, + rule_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Toggle a custom rule + + Args: + domain_id: The domain ID + + rule_id: The custom rule ID + + action: Enable or disable a custom rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not action: + raise ValueError(f"Expected a non-empty value for `action` but received {action!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._patch( + f"/waap/v1/domains/{domain_id}/custom-rules/{rule_id}/{action}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class CustomRulesResourceWithRawResponse: + def __init__(self, custom_rules: CustomRulesResource) -> None: + self._custom_rules = custom_rules + + self.create = to_raw_response_wrapper( + custom_rules.create, + ) + self.update = to_raw_response_wrapper( + custom_rules.update, + ) + self.list = to_raw_response_wrapper( + custom_rules.list, + ) + self.delete = to_raw_response_wrapper( + custom_rules.delete, + ) + self.delete_multiple = to_raw_response_wrapper( + custom_rules.delete_multiple, + ) + self.get = to_raw_response_wrapper( + custom_rules.get, + ) + self.toggle = to_raw_response_wrapper( + custom_rules.toggle, + ) + + +class AsyncCustomRulesResourceWithRawResponse: + def __init__(self, custom_rules: AsyncCustomRulesResource) -> None: + self._custom_rules = custom_rules + + self.create = async_to_raw_response_wrapper( + custom_rules.create, + ) + self.update = async_to_raw_response_wrapper( + custom_rules.update, + ) + self.list = async_to_raw_response_wrapper( + custom_rules.list, + ) + self.delete = async_to_raw_response_wrapper( + custom_rules.delete, + ) + self.delete_multiple = async_to_raw_response_wrapper( + custom_rules.delete_multiple, + ) + self.get = async_to_raw_response_wrapper( + custom_rules.get, + ) + self.toggle = async_to_raw_response_wrapper( + custom_rules.toggle, + ) + + +class CustomRulesResourceWithStreamingResponse: + def __init__(self, custom_rules: CustomRulesResource) -> None: + self._custom_rules = custom_rules + + self.create = to_streamed_response_wrapper( + custom_rules.create, + ) + self.update = to_streamed_response_wrapper( + custom_rules.update, + ) + self.list = to_streamed_response_wrapper( + custom_rules.list, + ) + self.delete = to_streamed_response_wrapper( + custom_rules.delete, + ) + self.delete_multiple = to_streamed_response_wrapper( + custom_rules.delete_multiple, + ) + self.get = to_streamed_response_wrapper( + custom_rules.get, + ) + self.toggle = to_streamed_response_wrapper( + custom_rules.toggle, + ) + + +class AsyncCustomRulesResourceWithStreamingResponse: + def __init__(self, custom_rules: AsyncCustomRulesResource) -> None: + self._custom_rules = custom_rules + + self.create = async_to_streamed_response_wrapper( + custom_rules.create, + ) + self.update = async_to_streamed_response_wrapper( + custom_rules.update, + ) + self.list = async_to_streamed_response_wrapper( + custom_rules.list, + ) + self.delete = async_to_streamed_response_wrapper( + custom_rules.delete, + ) + self.delete_multiple = async_to_streamed_response_wrapper( + custom_rules.delete_multiple, + ) + self.get = async_to_streamed_response_wrapper( + custom_rules.get, + ) + self.toggle = async_to_streamed_response_wrapper( + custom_rules.toggle, + ) diff --git a/src/gcore/resources/waap/domains/domains.py b/src/gcore/resources/waap/domains/domains.py new file mode 100644 index 00000000..644191c1 --- /dev/null +++ b/src/gcore/resources/waap/domains/domains.py @@ -0,0 +1,968 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal + +import httpx + +from .insights import ( + InsightsResource, + AsyncInsightsResource, + InsightsResourceWithRawResponse, + AsyncInsightsResourceWithRawResponse, + InsightsResourceWithStreamingResponse, + AsyncInsightsResourceWithStreamingResponse, +) +from .settings import ( + SettingsResource, + AsyncSettingsResource, + SettingsResourceWithRawResponse, + AsyncSettingsResourceWithRawResponse, + SettingsResourceWithStreamingResponse, + AsyncSettingsResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from .api_paths import ( + APIPathsResource, + AsyncAPIPathsResource, + APIPathsResourceWithRawResponse, + AsyncAPIPathsResourceWithRawResponse, + APIPathsResourceWithStreamingResponse, + AsyncAPIPathsResourceWithStreamingResponse, +) +from ...._compat import cached_property +from .statistics import ( + StatisticsResource, + AsyncStatisticsResource, + StatisticsResourceWithRawResponse, + AsyncStatisticsResourceWithRawResponse, + StatisticsResourceWithStreamingResponse, + AsyncStatisticsResourceWithStreamingResponse, +) +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .custom_rules import ( + CustomRulesResource, + AsyncCustomRulesResource, + CustomRulesResourceWithRawResponse, + AsyncCustomRulesResourceWithRawResponse, + CustomRulesResourceWithStreamingResponse, + AsyncCustomRulesResourceWithStreamingResponse, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ....types.waap import domain_list_params, domain_update_params +from .api_discovery import ( + APIDiscoveryResource, + AsyncAPIDiscoveryResource, + APIDiscoveryResourceWithRawResponse, + AsyncAPIDiscoveryResourceWithRawResponse, + APIDiscoveryResourceWithStreamingResponse, + AsyncAPIDiscoveryResourceWithStreamingResponse, +) +from .advanced_rules import ( + AdvancedRulesResource, + AsyncAdvancedRulesResource, + AdvancedRulesResourceWithRawResponse, + AsyncAdvancedRulesResourceWithRawResponse, + AdvancedRulesResourceWithStreamingResponse, + AsyncAdvancedRulesResourceWithStreamingResponse, +) +from .firewall_rules import ( + FirewallRulesResource, + AsyncFirewallRulesResource, + FirewallRulesResourceWithRawResponse, + AsyncFirewallRulesResourceWithRawResponse, + FirewallRulesResourceWithStreamingResponse, + AsyncFirewallRulesResourceWithStreamingResponse, +) +from ...._base_client import AsyncPaginator, make_request_options +from .api_path_groups import ( + APIPathGroupsResource, + AsyncAPIPathGroupsResource, + APIPathGroupsResourceWithRawResponse, + AsyncAPIPathGroupsResourceWithRawResponse, + APIPathGroupsResourceWithStreamingResponse, + AsyncAPIPathGroupsResourceWithStreamingResponse, +) +from .insight_silences import ( + InsightSilencesResource, + AsyncInsightSilencesResource, + InsightSilencesResourceWithRawResponse, + AsyncInsightSilencesResourceWithRawResponse, + InsightSilencesResourceWithStreamingResponse, + AsyncInsightSilencesResourceWithStreamingResponse, +) +from ....types.waap.waap_policy_mode import WaapPolicyMode +from ....types.waap.waap_summary_domain import WaapSummaryDomain +from ....types.waap.waap_detailed_domain import WaapDetailedDomain +from ....types.waap.domain_list_rule_sets_response import DomainListRuleSetsResponse + +__all__ = ["DomainsResource", "AsyncDomainsResource"] + + +class DomainsResource(SyncAPIResource): + @cached_property + def settings(self) -> SettingsResource: + return SettingsResource(self._client) + + @cached_property + def api_paths(self) -> APIPathsResource: + return APIPathsResource(self._client) + + @cached_property + def api_path_groups(self) -> APIPathGroupsResource: + return APIPathGroupsResource(self._client) + + @cached_property + def api_discovery(self) -> APIDiscoveryResource: + return APIDiscoveryResource(self._client) + + @cached_property + def insights(self) -> InsightsResource: + return InsightsResource(self._client) + + @cached_property + def insight_silences(self) -> InsightSilencesResource: + return InsightSilencesResource(self._client) + + @cached_property + def statistics(self) -> StatisticsResource: + return StatisticsResource(self._client) + + @cached_property + def custom_rules(self) -> CustomRulesResource: + return CustomRulesResource(self._client) + + @cached_property + def firewall_rules(self) -> FirewallRulesResource: + return FirewallRulesResource(self._client) + + @cached_property + def advanced_rules(self) -> AdvancedRulesResource: + return AdvancedRulesResource(self._client) + + @cached_property + def with_raw_response(self) -> DomainsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return DomainsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DomainsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return DomainsResourceWithStreamingResponse(self) + + def update( + self, + domain_id: int, + *, + status: Literal["active", "monitor"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Update Domain + + Args: + domain_id: The domain ID + + status: The current status of the domain + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._patch( + f"/waap/v1/domains/{domain_id}", + body=maybe_transform({"status": status}, domain_update_params.DomainUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + *, + ids: Iterable[int] | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Literal["id", "name", "status", "created_at", "-id", "-name", "-status", "-created_at"] | Omit = omit, + status: Literal["active", "bypass", "monitor", "locked"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapSummaryDomain]: + """ + Retrieve a list of domains associated with the client + + Args: + ids: Filter domains based on their IDs + + limit: Number of items to return + + name: Filter domains based on the domain name. Supports '\\**' as a wildcard character + + offset: Number of items to skip + + ordering: Sort the response by given field. + + status: Filter domains based on the domain status + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/waap/v1/domains", + page=SyncOffsetPage[WaapSummaryDomain], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "ids": ids, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + "status": status, + }, + domain_list_params.DomainListParams, + ), + ), + model=WaapSummaryDomain, + ) + + def delete( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete an inactive domain by ID. + + Only domains with status 'bypass' can be + deleted. + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/waap/v1/domains/{domain_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapDetailedDomain: + """ + Retrieve detailed information about a specific domain + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/waap/v1/domains/{domain_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapDetailedDomain, + ) + + def list_rule_sets( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DomainListRuleSetsResponse: + """ + Retrieve all rule sets linked to a particular domain + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/waap/v1/domains/{domain_id}/rule-sets", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DomainListRuleSetsResponse, + ) + + def toggle_policy( + self, + policy_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapPolicyMode: + """ + Modify the activation state of a policy associated with a domain + + Args: + domain_id: The domain ID + + policy_id: The ID of the policy to toggle + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not policy_id: + raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") + return self._patch( + f"/waap/v1/domains/{domain_id}/policies/{policy_id}/toggle", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapPolicyMode, + ) + + +class AsyncDomainsResource(AsyncAPIResource): + @cached_property + def settings(self) -> AsyncSettingsResource: + return AsyncSettingsResource(self._client) + + @cached_property + def api_paths(self) -> AsyncAPIPathsResource: + return AsyncAPIPathsResource(self._client) + + @cached_property + def api_path_groups(self) -> AsyncAPIPathGroupsResource: + return AsyncAPIPathGroupsResource(self._client) + + @cached_property + def api_discovery(self) -> AsyncAPIDiscoveryResource: + return AsyncAPIDiscoveryResource(self._client) + + @cached_property + def insights(self) -> AsyncInsightsResource: + return AsyncInsightsResource(self._client) + + @cached_property + def insight_silences(self) -> AsyncInsightSilencesResource: + return AsyncInsightSilencesResource(self._client) + + @cached_property + def statistics(self) -> AsyncStatisticsResource: + return AsyncStatisticsResource(self._client) + + @cached_property + def custom_rules(self) -> AsyncCustomRulesResource: + return AsyncCustomRulesResource(self._client) + + @cached_property + def firewall_rules(self) -> AsyncFirewallRulesResource: + return AsyncFirewallRulesResource(self._client) + + @cached_property + def advanced_rules(self) -> AsyncAdvancedRulesResource: + return AsyncAdvancedRulesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncDomainsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncDomainsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDomainsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncDomainsResourceWithStreamingResponse(self) + + async def update( + self, + domain_id: int, + *, + status: Literal["active", "monitor"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Update Domain + + Args: + domain_id: The domain ID + + status: The current status of the domain + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._patch( + f"/waap/v1/domains/{domain_id}", + body=await async_maybe_transform({"status": status}, domain_update_params.DomainUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + *, + ids: Iterable[int] | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Literal["id", "name", "status", "created_at", "-id", "-name", "-status", "-created_at"] | Omit = omit, + status: Literal["active", "bypass", "monitor", "locked"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapSummaryDomain, AsyncOffsetPage[WaapSummaryDomain]]: + """ + Retrieve a list of domains associated with the client + + Args: + ids: Filter domains based on their IDs + + limit: Number of items to return + + name: Filter domains based on the domain name. Supports '\\**' as a wildcard character + + offset: Number of items to skip + + ordering: Sort the response by given field. + + status: Filter domains based on the domain status + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/waap/v1/domains", + page=AsyncOffsetPage[WaapSummaryDomain], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "ids": ids, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + "status": status, + }, + domain_list_params.DomainListParams, + ), + ), + model=WaapSummaryDomain, + ) + + async def delete( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Delete an inactive domain by ID. + + Only domains with status 'bypass' can be + deleted. + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/waap/v1/domains/{domain_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapDetailedDomain: + """ + Retrieve detailed information about a specific domain + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/waap/v1/domains/{domain_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapDetailedDomain, + ) + + async def list_rule_sets( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> DomainListRuleSetsResponse: + """ + Retrieve all rule sets linked to a particular domain + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/waap/v1/domains/{domain_id}/rule-sets", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DomainListRuleSetsResponse, + ) + + async def toggle_policy( + self, + policy_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapPolicyMode: + """ + Modify the activation state of a policy associated with a domain + + Args: + domain_id: The domain ID + + policy_id: The ID of the policy to toggle + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not policy_id: + raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") + return await self._patch( + f"/waap/v1/domains/{domain_id}/policies/{policy_id}/toggle", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapPolicyMode, + ) + + +class DomainsResourceWithRawResponse: + def __init__(self, domains: DomainsResource) -> None: + self._domains = domains + + self.update = to_raw_response_wrapper( + domains.update, + ) + self.list = to_raw_response_wrapper( + domains.list, + ) + self.delete = to_raw_response_wrapper( + domains.delete, + ) + self.get = to_raw_response_wrapper( + domains.get, + ) + self.list_rule_sets = to_raw_response_wrapper( + domains.list_rule_sets, + ) + self.toggle_policy = to_raw_response_wrapper( + domains.toggle_policy, + ) + + @cached_property + def settings(self) -> SettingsResourceWithRawResponse: + return SettingsResourceWithRawResponse(self._domains.settings) + + @cached_property + def api_paths(self) -> APIPathsResourceWithRawResponse: + return APIPathsResourceWithRawResponse(self._domains.api_paths) + + @cached_property + def api_path_groups(self) -> APIPathGroupsResourceWithRawResponse: + return APIPathGroupsResourceWithRawResponse(self._domains.api_path_groups) + + @cached_property + def api_discovery(self) -> APIDiscoveryResourceWithRawResponse: + return APIDiscoveryResourceWithRawResponse(self._domains.api_discovery) + + @cached_property + def insights(self) -> InsightsResourceWithRawResponse: + return InsightsResourceWithRawResponse(self._domains.insights) + + @cached_property + def insight_silences(self) -> InsightSilencesResourceWithRawResponse: + return InsightSilencesResourceWithRawResponse(self._domains.insight_silences) + + @cached_property + def statistics(self) -> StatisticsResourceWithRawResponse: + return StatisticsResourceWithRawResponse(self._domains.statistics) + + @cached_property + def custom_rules(self) -> CustomRulesResourceWithRawResponse: + return CustomRulesResourceWithRawResponse(self._domains.custom_rules) + + @cached_property + def firewall_rules(self) -> FirewallRulesResourceWithRawResponse: + return FirewallRulesResourceWithRawResponse(self._domains.firewall_rules) + + @cached_property + def advanced_rules(self) -> AdvancedRulesResourceWithRawResponse: + return AdvancedRulesResourceWithRawResponse(self._domains.advanced_rules) + + +class AsyncDomainsResourceWithRawResponse: + def __init__(self, domains: AsyncDomainsResource) -> None: + self._domains = domains + + self.update = async_to_raw_response_wrapper( + domains.update, + ) + self.list = async_to_raw_response_wrapper( + domains.list, + ) + self.delete = async_to_raw_response_wrapper( + domains.delete, + ) + self.get = async_to_raw_response_wrapper( + domains.get, + ) + self.list_rule_sets = async_to_raw_response_wrapper( + domains.list_rule_sets, + ) + self.toggle_policy = async_to_raw_response_wrapper( + domains.toggle_policy, + ) + + @cached_property + def settings(self) -> AsyncSettingsResourceWithRawResponse: + return AsyncSettingsResourceWithRawResponse(self._domains.settings) + + @cached_property + def api_paths(self) -> AsyncAPIPathsResourceWithRawResponse: + return AsyncAPIPathsResourceWithRawResponse(self._domains.api_paths) + + @cached_property + def api_path_groups(self) -> AsyncAPIPathGroupsResourceWithRawResponse: + return AsyncAPIPathGroupsResourceWithRawResponse(self._domains.api_path_groups) + + @cached_property + def api_discovery(self) -> AsyncAPIDiscoveryResourceWithRawResponse: + return AsyncAPIDiscoveryResourceWithRawResponse(self._domains.api_discovery) + + @cached_property + def insights(self) -> AsyncInsightsResourceWithRawResponse: + return AsyncInsightsResourceWithRawResponse(self._domains.insights) + + @cached_property + def insight_silences(self) -> AsyncInsightSilencesResourceWithRawResponse: + return AsyncInsightSilencesResourceWithRawResponse(self._domains.insight_silences) + + @cached_property + def statistics(self) -> AsyncStatisticsResourceWithRawResponse: + return AsyncStatisticsResourceWithRawResponse(self._domains.statistics) + + @cached_property + def custom_rules(self) -> AsyncCustomRulesResourceWithRawResponse: + return AsyncCustomRulesResourceWithRawResponse(self._domains.custom_rules) + + @cached_property + def firewall_rules(self) -> AsyncFirewallRulesResourceWithRawResponse: + return AsyncFirewallRulesResourceWithRawResponse(self._domains.firewall_rules) + + @cached_property + def advanced_rules(self) -> AsyncAdvancedRulesResourceWithRawResponse: + return AsyncAdvancedRulesResourceWithRawResponse(self._domains.advanced_rules) + + +class DomainsResourceWithStreamingResponse: + def __init__(self, domains: DomainsResource) -> None: + self._domains = domains + + self.update = to_streamed_response_wrapper( + domains.update, + ) + self.list = to_streamed_response_wrapper( + domains.list, + ) + self.delete = to_streamed_response_wrapper( + domains.delete, + ) + self.get = to_streamed_response_wrapper( + domains.get, + ) + self.list_rule_sets = to_streamed_response_wrapper( + domains.list_rule_sets, + ) + self.toggle_policy = to_streamed_response_wrapper( + domains.toggle_policy, + ) + + @cached_property + def settings(self) -> SettingsResourceWithStreamingResponse: + return SettingsResourceWithStreamingResponse(self._domains.settings) + + @cached_property + def api_paths(self) -> APIPathsResourceWithStreamingResponse: + return APIPathsResourceWithStreamingResponse(self._domains.api_paths) + + @cached_property + def api_path_groups(self) -> APIPathGroupsResourceWithStreamingResponse: + return APIPathGroupsResourceWithStreamingResponse(self._domains.api_path_groups) + + @cached_property + def api_discovery(self) -> APIDiscoveryResourceWithStreamingResponse: + return APIDiscoveryResourceWithStreamingResponse(self._domains.api_discovery) + + @cached_property + def insights(self) -> InsightsResourceWithStreamingResponse: + return InsightsResourceWithStreamingResponse(self._domains.insights) + + @cached_property + def insight_silences(self) -> InsightSilencesResourceWithStreamingResponse: + return InsightSilencesResourceWithStreamingResponse(self._domains.insight_silences) + + @cached_property + def statistics(self) -> StatisticsResourceWithStreamingResponse: + return StatisticsResourceWithStreamingResponse(self._domains.statistics) + + @cached_property + def custom_rules(self) -> CustomRulesResourceWithStreamingResponse: + return CustomRulesResourceWithStreamingResponse(self._domains.custom_rules) + + @cached_property + def firewall_rules(self) -> FirewallRulesResourceWithStreamingResponse: + return FirewallRulesResourceWithStreamingResponse(self._domains.firewall_rules) + + @cached_property + def advanced_rules(self) -> AdvancedRulesResourceWithStreamingResponse: + return AdvancedRulesResourceWithStreamingResponse(self._domains.advanced_rules) + + +class AsyncDomainsResourceWithStreamingResponse: + def __init__(self, domains: AsyncDomainsResource) -> None: + self._domains = domains + + self.update = async_to_streamed_response_wrapper( + domains.update, + ) + self.list = async_to_streamed_response_wrapper( + domains.list, + ) + self.delete = async_to_streamed_response_wrapper( + domains.delete, + ) + self.get = async_to_streamed_response_wrapper( + domains.get, + ) + self.list_rule_sets = async_to_streamed_response_wrapper( + domains.list_rule_sets, + ) + self.toggle_policy = async_to_streamed_response_wrapper( + domains.toggle_policy, + ) + + @cached_property + def settings(self) -> AsyncSettingsResourceWithStreamingResponse: + return AsyncSettingsResourceWithStreamingResponse(self._domains.settings) + + @cached_property + def api_paths(self) -> AsyncAPIPathsResourceWithStreamingResponse: + return AsyncAPIPathsResourceWithStreamingResponse(self._domains.api_paths) + + @cached_property + def api_path_groups(self) -> AsyncAPIPathGroupsResourceWithStreamingResponse: + return AsyncAPIPathGroupsResourceWithStreamingResponse(self._domains.api_path_groups) + + @cached_property + def api_discovery(self) -> AsyncAPIDiscoveryResourceWithStreamingResponse: + return AsyncAPIDiscoveryResourceWithStreamingResponse(self._domains.api_discovery) + + @cached_property + def insights(self) -> AsyncInsightsResourceWithStreamingResponse: + return AsyncInsightsResourceWithStreamingResponse(self._domains.insights) + + @cached_property + def insight_silences(self) -> AsyncInsightSilencesResourceWithStreamingResponse: + return AsyncInsightSilencesResourceWithStreamingResponse(self._domains.insight_silences) + + @cached_property + def statistics(self) -> AsyncStatisticsResourceWithStreamingResponse: + return AsyncStatisticsResourceWithStreamingResponse(self._domains.statistics) + + @cached_property + def custom_rules(self) -> AsyncCustomRulesResourceWithStreamingResponse: + return AsyncCustomRulesResourceWithStreamingResponse(self._domains.custom_rules) + + @cached_property + def firewall_rules(self) -> AsyncFirewallRulesResourceWithStreamingResponse: + return AsyncFirewallRulesResourceWithStreamingResponse(self._domains.firewall_rules) + + @cached_property + def advanced_rules(self) -> AsyncAdvancedRulesResourceWithStreamingResponse: + return AsyncAdvancedRulesResourceWithStreamingResponse(self._domains.advanced_rules) diff --git a/src/gcore/resources/waap/domains/firewall_rules.py b/src/gcore/resources/waap/domains/firewall_rules.py new file mode 100644 index 00000000..3dbdde0b --- /dev/null +++ b/src/gcore/resources/waap/domains/firewall_rules.py @@ -0,0 +1,882 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.waap.domains import ( + firewall_rule_list_params, + firewall_rule_create_params, + firewall_rule_update_params, + firewall_rule_delete_multiple_params, +) +from ....types.waap.domains.waap_firewall_rule import WaapFirewallRule + +__all__ = ["FirewallRulesResource", "AsyncFirewallRulesResource"] + + +class FirewallRulesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> FirewallRulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return FirewallRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FirewallRulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return FirewallRulesResourceWithStreamingResponse(self) + + def create( + self, + domain_id: int, + *, + action: firewall_rule_create_params.Action, + conditions: Iterable[firewall_rule_create_params.Condition], + enabled: bool, + name: str, + description: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapFirewallRule: + """ + Create a firewall rule + + Args: + domain_id: The domain ID + + action: The action that the rule takes when triggered + + conditions: The condition required for the WAAP engine to trigger the rule. + + enabled: Whether or not the rule is enabled + + name: The name assigned to the rule + + description: The description assigned to the rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/waap/v1/domains/{domain_id}/firewall-rules", + body=maybe_transform( + { + "action": action, + "conditions": conditions, + "enabled": enabled, + "name": name, + "description": description, + }, + firewall_rule_create_params.FirewallRuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapFirewallRule, + ) + + def update( + self, + rule_id: int, + *, + domain_id: int, + action: Optional[firewall_rule_update_params.Action] | Omit = omit, + conditions: Optional[Iterable[firewall_rule_update_params.Condition]] | Omit = omit, + description: Optional[str] | Omit = omit, + enabled: Optional[bool] | Omit = omit, + name: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Only properties present in the request will be updated + + Args: + domain_id: The domain ID + + rule_id: The firewall rule ID + + action: The action that a firewall rule takes when triggered + + conditions: The condition required for the WAAP engine to trigger the rule. + + description: The description assigned to the rule + + enabled: Whether or not the rule is enabled + + name: The name assigned to the rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._patch( + f"/waap/v1/domains/{domain_id}/firewall-rules/{rule_id}", + body=maybe_transform( + { + "action": action, + "conditions": conditions, + "description": description, + "enabled": enabled, + "name": name, + }, + firewall_rule_update_params.FirewallRuleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + domain_id: int, + *, + action: Literal["allow", "block"] | Omit = omit, + description: str | Omit = omit, + enabled: bool | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Optional[ + Literal[ + "id", "name", "description", "enabled", "action", "-id", "-name", "-description", "-enabled", "-action" + ] + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapFirewallRule]: + """ + Extracts a list of firewall rules assigned to a domain, offering filter, + ordering, and pagination capabilities + + Args: + domain_id: The domain ID + + action: Filter to refine results by specific firewall actions + + description: Filter rules based on their description. Supports '\\**' as a wildcard character. + + enabled: Filter rules based on their active status + + limit: Number of items to return + + name: Filter rules based on their name. Supports '\\**' as a wildcard character. + + offset: Number of items to skip + + ordering: Determine the field to order results by + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/firewall-rules", + page=SyncOffsetPage[WaapFirewallRule], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "action": action, + "description": description, + "enabled": enabled, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + }, + firewall_rule_list_params.FirewallRuleListParams, + ), + ), + model=WaapFirewallRule, + ) + + def delete( + self, + rule_id: int, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a firewall rule + + Args: + domain_id: The domain ID + + rule_id: The firewall rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/waap/v1/domains/{domain_id}/firewall-rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def delete_multiple( + self, + domain_id: int, + *, + rule_ids: Iterable[int], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete multiple WAAP rules + + Args: + domain_id: The domain ID + + rule_ids: The IDs of the rules to delete + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/waap/v1/domains/{domain_id}/firewall-rules/bulk_delete", + body=maybe_transform( + {"rule_ids": rule_ids}, firewall_rule_delete_multiple_params.FirewallRuleDeleteMultipleParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + rule_id: int, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapFirewallRule: + """ + Extracts a specific firewall rule assigned to a domain + + Args: + domain_id: The domain ID + + rule_id: The firewall rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/waap/v1/domains/{domain_id}/firewall-rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapFirewallRule, + ) + + def toggle( + self, + action: Literal["enable", "disable"], + *, + domain_id: int, + rule_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Toggle a firewall rule + + Args: + domain_id: The domain ID + + rule_id: The firewall rule ID + + action: Enable or disable a firewall rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not action: + raise ValueError(f"Expected a non-empty value for `action` but received {action!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._patch( + f"/waap/v1/domains/{domain_id}/firewall-rules/{rule_id}/{action}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncFirewallRulesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncFirewallRulesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncFirewallRulesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFirewallRulesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncFirewallRulesResourceWithStreamingResponse(self) + + async def create( + self, + domain_id: int, + *, + action: firewall_rule_create_params.Action, + conditions: Iterable[firewall_rule_create_params.Condition], + enabled: bool, + name: str, + description: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapFirewallRule: + """ + Create a firewall rule + + Args: + domain_id: The domain ID + + action: The action that the rule takes when triggered + + conditions: The condition required for the WAAP engine to trigger the rule. + + enabled: Whether or not the rule is enabled + + name: The name assigned to the rule + + description: The description assigned to the rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/waap/v1/domains/{domain_id}/firewall-rules", + body=await async_maybe_transform( + { + "action": action, + "conditions": conditions, + "enabled": enabled, + "name": name, + "description": description, + }, + firewall_rule_create_params.FirewallRuleCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapFirewallRule, + ) + + async def update( + self, + rule_id: int, + *, + domain_id: int, + action: Optional[firewall_rule_update_params.Action] | Omit = omit, + conditions: Optional[Iterable[firewall_rule_update_params.Condition]] | Omit = omit, + description: Optional[str] | Omit = omit, + enabled: Optional[bool] | Omit = omit, + name: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Only properties present in the request will be updated + + Args: + domain_id: The domain ID + + rule_id: The firewall rule ID + + action: The action that a firewall rule takes when triggered + + conditions: The condition required for the WAAP engine to trigger the rule. + + description: The description assigned to the rule + + enabled: Whether or not the rule is enabled + + name: The name assigned to the rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._patch( + f"/waap/v1/domains/{domain_id}/firewall-rules/{rule_id}", + body=await async_maybe_transform( + { + "action": action, + "conditions": conditions, + "description": description, + "enabled": enabled, + "name": name, + }, + firewall_rule_update_params.FirewallRuleUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + domain_id: int, + *, + action: Literal["allow", "block"] | Omit = omit, + description: str | Omit = omit, + enabled: bool | Omit = omit, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Optional[ + Literal[ + "id", "name", "description", "enabled", "action", "-id", "-name", "-description", "-enabled", "-action" + ] + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapFirewallRule, AsyncOffsetPage[WaapFirewallRule]]: + """ + Extracts a list of firewall rules assigned to a domain, offering filter, + ordering, and pagination capabilities + + Args: + domain_id: The domain ID + + action: Filter to refine results by specific firewall actions + + description: Filter rules based on their description. Supports '\\**' as a wildcard character. + + enabled: Filter rules based on their active status + + limit: Number of items to return + + name: Filter rules based on their name. Supports '\\**' as a wildcard character. + + offset: Number of items to skip + + ordering: Determine the field to order results by + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/firewall-rules", + page=AsyncOffsetPage[WaapFirewallRule], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "action": action, + "description": description, + "enabled": enabled, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + }, + firewall_rule_list_params.FirewallRuleListParams, + ), + ), + model=WaapFirewallRule, + ) + + async def delete( + self, + rule_id: int, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete a firewall rule + + Args: + domain_id: The domain ID + + rule_id: The firewall rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/waap/v1/domains/{domain_id}/firewall-rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def delete_multiple( + self, + domain_id: int, + *, + rule_ids: Iterable[int], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete multiple WAAP rules + + Args: + domain_id: The domain ID + + rule_ids: The IDs of the rules to delete + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/waap/v1/domains/{domain_id}/firewall-rules/bulk_delete", + body=await async_maybe_transform( + {"rule_ids": rule_ids}, firewall_rule_delete_multiple_params.FirewallRuleDeleteMultipleParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + rule_id: int, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapFirewallRule: + """ + Extracts a specific firewall rule assigned to a domain + + Args: + domain_id: The domain ID + + rule_id: The firewall rule ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/waap/v1/domains/{domain_id}/firewall-rules/{rule_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapFirewallRule, + ) + + async def toggle( + self, + action: Literal["enable", "disable"], + *, + domain_id: int, + rule_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Toggle a firewall rule + + Args: + domain_id: The domain ID + + rule_id: The firewall rule ID + + action: Enable or disable a firewall rule + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not action: + raise ValueError(f"Expected a non-empty value for `action` but received {action!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._patch( + f"/waap/v1/domains/{domain_id}/firewall-rules/{rule_id}/{action}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class FirewallRulesResourceWithRawResponse: + def __init__(self, firewall_rules: FirewallRulesResource) -> None: + self._firewall_rules = firewall_rules + + self.create = to_raw_response_wrapper( + firewall_rules.create, + ) + self.update = to_raw_response_wrapper( + firewall_rules.update, + ) + self.list = to_raw_response_wrapper( + firewall_rules.list, + ) + self.delete = to_raw_response_wrapper( + firewall_rules.delete, + ) + self.delete_multiple = to_raw_response_wrapper( + firewall_rules.delete_multiple, + ) + self.get = to_raw_response_wrapper( + firewall_rules.get, + ) + self.toggle = to_raw_response_wrapper( + firewall_rules.toggle, + ) + + +class AsyncFirewallRulesResourceWithRawResponse: + def __init__(self, firewall_rules: AsyncFirewallRulesResource) -> None: + self._firewall_rules = firewall_rules + + self.create = async_to_raw_response_wrapper( + firewall_rules.create, + ) + self.update = async_to_raw_response_wrapper( + firewall_rules.update, + ) + self.list = async_to_raw_response_wrapper( + firewall_rules.list, + ) + self.delete = async_to_raw_response_wrapper( + firewall_rules.delete, + ) + self.delete_multiple = async_to_raw_response_wrapper( + firewall_rules.delete_multiple, + ) + self.get = async_to_raw_response_wrapper( + firewall_rules.get, + ) + self.toggle = async_to_raw_response_wrapper( + firewall_rules.toggle, + ) + + +class FirewallRulesResourceWithStreamingResponse: + def __init__(self, firewall_rules: FirewallRulesResource) -> None: + self._firewall_rules = firewall_rules + + self.create = to_streamed_response_wrapper( + firewall_rules.create, + ) + self.update = to_streamed_response_wrapper( + firewall_rules.update, + ) + self.list = to_streamed_response_wrapper( + firewall_rules.list, + ) + self.delete = to_streamed_response_wrapper( + firewall_rules.delete, + ) + self.delete_multiple = to_streamed_response_wrapper( + firewall_rules.delete_multiple, + ) + self.get = to_streamed_response_wrapper( + firewall_rules.get, + ) + self.toggle = to_streamed_response_wrapper( + firewall_rules.toggle, + ) + + +class AsyncFirewallRulesResourceWithStreamingResponse: + def __init__(self, firewall_rules: AsyncFirewallRulesResource) -> None: + self._firewall_rules = firewall_rules + + self.create = async_to_streamed_response_wrapper( + firewall_rules.create, + ) + self.update = async_to_streamed_response_wrapper( + firewall_rules.update, + ) + self.list = async_to_streamed_response_wrapper( + firewall_rules.list, + ) + self.delete = async_to_streamed_response_wrapper( + firewall_rules.delete, + ) + self.delete_multiple = async_to_streamed_response_wrapper( + firewall_rules.delete_multiple, + ) + self.get = async_to_streamed_response_wrapper( + firewall_rules.get, + ) + self.toggle = async_to_streamed_response_wrapper( + firewall_rules.toggle, + ) diff --git a/src/gcore/resources/waap/domains/insight_silences.py b/src/gcore/resources/waap/domains/insight_silences.py new file mode 100644 index 00000000..8b57783e --- /dev/null +++ b/src/gcore/resources/waap/domains/insight_silences.py @@ -0,0 +1,712 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Optional +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.waap.domains import ( + insight_silence_list_params, + insight_silence_create_params, + insight_silence_update_params, +) +from ....types.waap.domains.waap_insight_silence import WaapInsightSilence + +__all__ = ["InsightSilencesResource", "AsyncInsightSilencesResource"] + + +class InsightSilencesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> InsightSilencesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return InsightSilencesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InsightSilencesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return InsightSilencesResourceWithStreamingResponse(self) + + def create( + self, + domain_id: int, + *, + author: str, + comment: str, + insight_type: str, + labels: Dict[str, str], + expire_at: Union[str, datetime, None] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapInsightSilence: + """Create a new insight silence for a specified domain. + + Insight silences help in + temporarily disabling certain insights based on specific criteria. + + Args: + domain_id: The domain ID + + author: The author of the silence + + comment: A comment explaining the reason for the silence + + insight_type: The slug of the insight type + + labels: A hash table of label names and values that apply to the insight silence + + expire_at: The date and time the silence expires in ISO 8601 format + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + f"/waap/v1/domains/{domain_id}/insight-silences", + body=maybe_transform( + { + "author": author, + "comment": comment, + "insight_type": insight_type, + "labels": labels, + "expire_at": expire_at, + }, + insight_silence_create_params.InsightSilenceCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapInsightSilence, + ) + + def update( + self, + silence_id: str, + *, + domain_id: int, + author: str, + comment: str, + expire_at: Union[str, datetime, None], + labels: Dict[str, str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapInsightSilence: + """ + Update an insight silence for a specific domain. + + Args: + domain_id: The domain ID + + silence_id: A generated unique identifier for the silence + + author: The author of the silence + + comment: A comment explaining the reason for the silence + + expire_at: The date and time the silence expires in ISO 8601 format + + labels: A hash table of label names and values that apply to the insight silence + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not silence_id: + raise ValueError(f"Expected a non-empty value for `silence_id` but received {silence_id!r}") + return self._patch( + f"/waap/v1/domains/{domain_id}/insight-silences/{silence_id}", + body=maybe_transform( + { + "author": author, + "comment": comment, + "expire_at": expire_at, + "labels": labels, + }, + insight_silence_update_params.InsightSilenceUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapInsightSilence, + ) + + def list( + self, + domain_id: int, + *, + id: Optional[SequenceNotStr[str]] | Omit = omit, + author: Optional[str] | Omit = omit, + comment: Optional[str] | Omit = omit, + insight_type: Optional[SequenceNotStr[str]] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + ordering: Literal[ + "id", + "-id", + "insight_type", + "-insight_type", + "comment", + "-comment", + "author", + "-author", + "expire_at", + "-expire_at", + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapInsightSilence]: + """ + Retrieve a list of insight silences for a specific domain + + Args: + domain_id: The domain ID + + id: The ID of the insight silence + + author: The author of the insight silence + + comment: The comment of the insight silence + + insight_type: The type of the insight silence + + limit: Number of items to return + + offset: Number of items to skip + + ordering: Sort the response by given field. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/insight-silences", + page=SyncOffsetPage[WaapInsightSilence], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "id": id, + "author": author, + "comment": comment, + "insight_type": insight_type, + "limit": limit, + "offset": offset, + "ordering": ordering, + }, + insight_silence_list_params.InsightSilenceListParams, + ), + ), + model=WaapInsightSilence, + ) + + def delete( + self, + silence_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete an insight silence for a specific domain. + + Args: + domain_id: The domain ID + + silence_id: A generated unique identifier for the silence + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not silence_id: + raise ValueError(f"Expected a non-empty value for `silence_id` but received {silence_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/waap/v1/domains/{domain_id}/insight-silences/{silence_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + silence_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapInsightSilence: + """ + Retrieve a specific insight silence for a specific domain + + Args: + domain_id: The domain ID + + silence_id: A generated unique identifier for the silence + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not silence_id: + raise ValueError(f"Expected a non-empty value for `silence_id` but received {silence_id!r}") + return self._get( + f"/waap/v1/domains/{domain_id}/insight-silences/{silence_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapInsightSilence, + ) + + +class AsyncInsightSilencesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncInsightSilencesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncInsightSilencesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInsightSilencesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncInsightSilencesResourceWithStreamingResponse(self) + + async def create( + self, + domain_id: int, + *, + author: str, + comment: str, + insight_type: str, + labels: Dict[str, str], + expire_at: Union[str, datetime, None] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapInsightSilence: + """Create a new insight silence for a specified domain. + + Insight silences help in + temporarily disabling certain insights based on specific criteria. + + Args: + domain_id: The domain ID + + author: The author of the silence + + comment: A comment explaining the reason for the silence + + insight_type: The slug of the insight type + + labels: A hash table of label names and values that apply to the insight silence + + expire_at: The date and time the silence expires in ISO 8601 format + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + f"/waap/v1/domains/{domain_id}/insight-silences", + body=await async_maybe_transform( + { + "author": author, + "comment": comment, + "insight_type": insight_type, + "labels": labels, + "expire_at": expire_at, + }, + insight_silence_create_params.InsightSilenceCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapInsightSilence, + ) + + async def update( + self, + silence_id: str, + *, + domain_id: int, + author: str, + comment: str, + expire_at: Union[str, datetime, None], + labels: Dict[str, str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapInsightSilence: + """ + Update an insight silence for a specific domain. + + Args: + domain_id: The domain ID + + silence_id: A generated unique identifier for the silence + + author: The author of the silence + + comment: A comment explaining the reason for the silence + + expire_at: The date and time the silence expires in ISO 8601 format + + labels: A hash table of label names and values that apply to the insight silence + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not silence_id: + raise ValueError(f"Expected a non-empty value for `silence_id` but received {silence_id!r}") + return await self._patch( + f"/waap/v1/domains/{domain_id}/insight-silences/{silence_id}", + body=await async_maybe_transform( + { + "author": author, + "comment": comment, + "expire_at": expire_at, + "labels": labels, + }, + insight_silence_update_params.InsightSilenceUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapInsightSilence, + ) + + def list( + self, + domain_id: int, + *, + id: Optional[SequenceNotStr[str]] | Omit = omit, + author: Optional[str] | Omit = omit, + comment: Optional[str] | Omit = omit, + insight_type: Optional[SequenceNotStr[str]] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + ordering: Literal[ + "id", + "-id", + "insight_type", + "-insight_type", + "comment", + "-comment", + "author", + "-author", + "expire_at", + "-expire_at", + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapInsightSilence, AsyncOffsetPage[WaapInsightSilence]]: + """ + Retrieve a list of insight silences for a specific domain + + Args: + domain_id: The domain ID + + id: The ID of the insight silence + + author: The author of the insight silence + + comment: The comment of the insight silence + + insight_type: The type of the insight silence + + limit: Number of items to return + + offset: Number of items to skip + + ordering: Sort the response by given field. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/insight-silences", + page=AsyncOffsetPage[WaapInsightSilence], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "id": id, + "author": author, + "comment": comment, + "insight_type": insight_type, + "limit": limit, + "offset": offset, + "ordering": ordering, + }, + insight_silence_list_params.InsightSilenceListParams, + ), + ), + model=WaapInsightSilence, + ) + + async def delete( + self, + silence_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Delete an insight silence for a specific domain. + + Args: + domain_id: The domain ID + + silence_id: A generated unique identifier for the silence + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not silence_id: + raise ValueError(f"Expected a non-empty value for `silence_id` but received {silence_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/waap/v1/domains/{domain_id}/insight-silences/{silence_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + silence_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapInsightSilence: + """ + Retrieve a specific insight silence for a specific domain + + Args: + domain_id: The domain ID + + silence_id: A generated unique identifier for the silence + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not silence_id: + raise ValueError(f"Expected a non-empty value for `silence_id` but received {silence_id!r}") + return await self._get( + f"/waap/v1/domains/{domain_id}/insight-silences/{silence_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapInsightSilence, + ) + + +class InsightSilencesResourceWithRawResponse: + def __init__(self, insight_silences: InsightSilencesResource) -> None: + self._insight_silences = insight_silences + + self.create = to_raw_response_wrapper( + insight_silences.create, + ) + self.update = to_raw_response_wrapper( + insight_silences.update, + ) + self.list = to_raw_response_wrapper( + insight_silences.list, + ) + self.delete = to_raw_response_wrapper( + insight_silences.delete, + ) + self.get = to_raw_response_wrapper( + insight_silences.get, + ) + + +class AsyncInsightSilencesResourceWithRawResponse: + def __init__(self, insight_silences: AsyncInsightSilencesResource) -> None: + self._insight_silences = insight_silences + + self.create = async_to_raw_response_wrapper( + insight_silences.create, + ) + self.update = async_to_raw_response_wrapper( + insight_silences.update, + ) + self.list = async_to_raw_response_wrapper( + insight_silences.list, + ) + self.delete = async_to_raw_response_wrapper( + insight_silences.delete, + ) + self.get = async_to_raw_response_wrapper( + insight_silences.get, + ) + + +class InsightSilencesResourceWithStreamingResponse: + def __init__(self, insight_silences: InsightSilencesResource) -> None: + self._insight_silences = insight_silences + + self.create = to_streamed_response_wrapper( + insight_silences.create, + ) + self.update = to_streamed_response_wrapper( + insight_silences.update, + ) + self.list = to_streamed_response_wrapper( + insight_silences.list, + ) + self.delete = to_streamed_response_wrapper( + insight_silences.delete, + ) + self.get = to_streamed_response_wrapper( + insight_silences.get, + ) + + +class AsyncInsightSilencesResourceWithStreamingResponse: + def __init__(self, insight_silences: AsyncInsightSilencesResource) -> None: + self._insight_silences = insight_silences + + self.create = async_to_streamed_response_wrapper( + insight_silences.create, + ) + self.update = async_to_streamed_response_wrapper( + insight_silences.update, + ) + self.list = async_to_streamed_response_wrapper( + insight_silences.list, + ) + self.delete = async_to_streamed_response_wrapper( + insight_silences.delete, + ) + self.get = async_to_streamed_response_wrapper( + insight_silences.get, + ) diff --git a/src/gcore/resources/waap/domains/insights.py b/src/gcore/resources/waap/domains/insights.py new file mode 100644 index 00000000..924fe5e2 --- /dev/null +++ b/src/gcore/resources/waap/domains/insights.py @@ -0,0 +1,451 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.waap.domains import insight_list_params, insight_replace_params +from ....types.waap.domains.waap_insight import WaapInsight + +__all__ = ["InsightsResource", "AsyncInsightsResource"] + + +class InsightsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> InsightsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return InsightsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InsightsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return InsightsResourceWithStreamingResponse(self) + + def list( + self, + domain_id: int, + *, + id: Optional[SequenceNotStr[str]] | Omit = omit, + description: Optional[str] | Omit = omit, + insight_type: Optional[SequenceNotStr[str]] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + ordering: Literal[ + "id", + "-id", + "insight_type", + "-insight_type", + "first_seen", + "-first_seen", + "last_seen", + "-last_seen", + "last_status_change", + "-last_status_change", + "status", + "-status", + ] + | Omit = omit, + status: Optional[List[Literal["OPEN", "ACKED", "CLOSED"]]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapInsight]: + """ + Retrieve a list of insights for a specific domain. + + Args: + domain_id: The domain ID + + id: The ID of the insight + + description: The description of the insight. Supports '\\**' as a wildcard. + + insight_type: The type of the insight + + limit: Number of items to return + + offset: Number of items to skip + + ordering: Sort the response by given field. + + status: The status of the insight + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/insights", + page=SyncOffsetPage[WaapInsight], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "id": id, + "description": description, + "insight_type": insight_type, + "limit": limit, + "offset": offset, + "ordering": ordering, + "status": status, + }, + insight_list_params.InsightListParams, + ), + ), + model=WaapInsight, + ) + + def get( + self, + insight_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapInsight: + """ + Retrieve a specific insight for a specific domain. + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not insight_id: + raise ValueError(f"Expected a non-empty value for `insight_id` but received {insight_id!r}") + return self._get( + f"/waap/v1/domains/{domain_id}/insights/{insight_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapInsight, + ) + + def replace( + self, + insight_id: str, + *, + domain_id: int, + status: Literal["OPEN", "ACKED", "CLOSED"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapInsight: + """ + Update the status of an insight for a specific domain. + + Args: + domain_id: The domain ID + + insight_id: The ID of the insight + + status: The status of the insight + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not insight_id: + raise ValueError(f"Expected a non-empty value for `insight_id` but received {insight_id!r}") + return self._put( + f"/waap/v1/domains/{domain_id}/insights/{insight_id}", + body=maybe_transform({"status": status}, insight_replace_params.InsightReplaceParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapInsight, + ) + + +class AsyncInsightsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncInsightsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncInsightsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInsightsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncInsightsResourceWithStreamingResponse(self) + + def list( + self, + domain_id: int, + *, + id: Optional[SequenceNotStr[str]] | Omit = omit, + description: Optional[str] | Omit = omit, + insight_type: Optional[SequenceNotStr[str]] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + ordering: Literal[ + "id", + "-id", + "insight_type", + "-insight_type", + "first_seen", + "-first_seen", + "last_seen", + "-last_seen", + "last_status_change", + "-last_status_change", + "status", + "-status", + ] + | Omit = omit, + status: Optional[List[Literal["OPEN", "ACKED", "CLOSED"]]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapInsight, AsyncOffsetPage[WaapInsight]]: + """ + Retrieve a list of insights for a specific domain. + + Args: + domain_id: The domain ID + + id: The ID of the insight + + description: The description of the insight. Supports '\\**' as a wildcard. + + insight_type: The type of the insight + + limit: Number of items to return + + offset: Number of items to skip + + ordering: Sort the response by given field. + + status: The status of the insight + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/insights", + page=AsyncOffsetPage[WaapInsight], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "id": id, + "description": description, + "insight_type": insight_type, + "limit": limit, + "offset": offset, + "ordering": ordering, + "status": status, + }, + insight_list_params.InsightListParams, + ), + ), + model=WaapInsight, + ) + + async def get( + self, + insight_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapInsight: + """ + Retrieve a specific insight for a specific domain. + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not insight_id: + raise ValueError(f"Expected a non-empty value for `insight_id` but received {insight_id!r}") + return await self._get( + f"/waap/v1/domains/{domain_id}/insights/{insight_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapInsight, + ) + + async def replace( + self, + insight_id: str, + *, + domain_id: int, + status: Literal["OPEN", "ACKED", "CLOSED"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapInsight: + """ + Update the status of an insight for a specific domain. + + Args: + domain_id: The domain ID + + insight_id: The ID of the insight + + status: The status of the insight + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not insight_id: + raise ValueError(f"Expected a non-empty value for `insight_id` but received {insight_id!r}") + return await self._put( + f"/waap/v1/domains/{domain_id}/insights/{insight_id}", + body=await async_maybe_transform({"status": status}, insight_replace_params.InsightReplaceParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapInsight, + ) + + +class InsightsResourceWithRawResponse: + def __init__(self, insights: InsightsResource) -> None: + self._insights = insights + + self.list = to_raw_response_wrapper( + insights.list, + ) + self.get = to_raw_response_wrapper( + insights.get, + ) + self.replace = to_raw_response_wrapper( + insights.replace, + ) + + +class AsyncInsightsResourceWithRawResponse: + def __init__(self, insights: AsyncInsightsResource) -> None: + self._insights = insights + + self.list = async_to_raw_response_wrapper( + insights.list, + ) + self.get = async_to_raw_response_wrapper( + insights.get, + ) + self.replace = async_to_raw_response_wrapper( + insights.replace, + ) + + +class InsightsResourceWithStreamingResponse: + def __init__(self, insights: InsightsResource) -> None: + self._insights = insights + + self.list = to_streamed_response_wrapper( + insights.list, + ) + self.get = to_streamed_response_wrapper( + insights.get, + ) + self.replace = to_streamed_response_wrapper( + insights.replace, + ) + + +class AsyncInsightsResourceWithStreamingResponse: + def __init__(self, insights: AsyncInsightsResource) -> None: + self._insights = insights + + self.list = async_to_streamed_response_wrapper( + insights.list, + ) + self.get = async_to_streamed_response_wrapper( + insights.get, + ) + self.replace = async_to_streamed_response_wrapper( + insights.replace, + ) diff --git a/src/gcore/resources/waap/domains/settings.py b/src/gcore/resources/waap/domains/settings.py new file mode 100644 index 00000000..fcaabeaa --- /dev/null +++ b/src/gcore/resources/waap/domains/settings.py @@ -0,0 +1,271 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.waap.domains import setting_update_params +from ....types.waap.waap_domain_settings_model import WaapDomainSettingsModel + +__all__ = ["SettingsResource", "AsyncSettingsResource"] + + +class SettingsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> SettingsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return SettingsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SettingsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return SettingsResourceWithStreamingResponse(self) + + def update( + self, + domain_id: int, + *, + api: setting_update_params.API | Omit = omit, + ddos: setting_update_params.DDOS | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Update settings for a specific domain + + Args: + domain_id: The domain ID + + api: Editable API settings of a domain + + ddos: Editable DDoS settings for a domain. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._patch( + f"/waap/v1/domains/{domain_id}/settings", + body=maybe_transform( + { + "api": api, + "ddos": ddos, + }, + setting_update_params.SettingUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def get( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapDomainSettingsModel: + """ + Retrieve settings for a specific domain + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/waap/v1/domains/{domain_id}/settings", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapDomainSettingsModel, + ) + + +class AsyncSettingsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncSettingsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncSettingsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSettingsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncSettingsResourceWithStreamingResponse(self) + + async def update( + self, + domain_id: int, + *, + api: setting_update_params.API | Omit = omit, + ddos: setting_update_params.DDOS | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Update settings for a specific domain + + Args: + domain_id: The domain ID + + api: Editable API settings of a domain + + ddos: Editable DDoS settings for a domain. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._patch( + f"/waap/v1/domains/{domain_id}/settings", + body=await async_maybe_transform( + { + "api": api, + "ddos": ddos, + }, + setting_update_params.SettingUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def get( + self, + domain_id: int, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapDomainSettingsModel: + """ + Retrieve settings for a specific domain + + Args: + domain_id: The domain ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/waap/v1/domains/{domain_id}/settings", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapDomainSettingsModel, + ) + + +class SettingsResourceWithRawResponse: + def __init__(self, settings: SettingsResource) -> None: + self._settings = settings + + self.update = to_raw_response_wrapper( + settings.update, + ) + self.get = to_raw_response_wrapper( + settings.get, + ) + + +class AsyncSettingsResourceWithRawResponse: + def __init__(self, settings: AsyncSettingsResource) -> None: + self._settings = settings + + self.update = async_to_raw_response_wrapper( + settings.update, + ) + self.get = async_to_raw_response_wrapper( + settings.get, + ) + + +class SettingsResourceWithStreamingResponse: + def __init__(self, settings: SettingsResource) -> None: + self._settings = settings + + self.update = to_streamed_response_wrapper( + settings.update, + ) + self.get = to_streamed_response_wrapper( + settings.get, + ) + + +class AsyncSettingsResourceWithStreamingResponse: + def __init__(self, settings: AsyncSettingsResource) -> None: + self._settings = settings + + self.update = async_to_streamed_response_wrapper( + settings.update, + ) + self.get = async_to_streamed_response_wrapper( + settings.get, + ) diff --git a/src/gcore/resources/waap/domains/statistics.py b/src/gcore/resources/waap/domains/statistics.py new file mode 100644 index 00000000..e990b52d --- /dev/null +++ b/src/gcore/resources/waap/domains/statistics.py @@ -0,0 +1,1006 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import typing_extensions +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncOffsetPage, AsyncOffsetPage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.waap.domains import ( + statistic_get_ddos_info_params, + statistic_get_ddos_attacks_params, + statistic_get_traffic_series_params, + statistic_get_requests_series_params, + statistic_get_events_aggregated_params, +) +from ....types.waap.domains.waap_ddos_info import WaapDDOSInfo +from ....types.waap.domains.waap_ddos_attack import WaapDDOSAttack +from ....types.waap.domains.waap_request_details import WaapRequestDetails +from ....types.waap.domains.waap_request_summary import WaapRequestSummary +from ....types.waap.domains.waap_event_statistics import WaapEventStatistics +from ....types.waap.domains.statistic_get_traffic_series_response import StatisticGetTrafficSeriesResponse + +__all__ = ["StatisticsResource", "AsyncStatisticsResource"] + + +class StatisticsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> StatisticsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return StatisticsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> StatisticsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return StatisticsResourceWithStreamingResponse(self) + + def get_ddos_attacks( + self, + domain_id: int, + *, + end_time: Union[str, datetime, None] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + ordering: Literal["start_time", "-start_time", "end_time", "-end_time"] | Omit = omit, + start_time: Union[str, datetime, None] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapDDOSAttack]: + """ + Retrieve a domain's DDoS attacks + + Args: + domain_id: The domain ID + + end_time: Filter attacks up to a specified end date in ISO 8601 format + + limit: Number of items to return + + offset: Number of items to skip + + ordering: Sort the response by given field. + + start_time: Filter attacks starting from a specified date in ISO 8601 format + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/ddos-attacks", + page=SyncOffsetPage[WaapDDOSAttack], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "end_time": end_time, + "limit": limit, + "offset": offset, + "ordering": ordering, + "start_time": start_time, + }, + statistic_get_ddos_attacks_params.StatisticGetDDOSAttacksParams, + ), + ), + model=WaapDDOSAttack, + ) + + def get_ddos_info( + self, + domain_id: int, + *, + group_by: Literal["URL", "User-Agent", "IP"], + start: str, + end: Optional[str] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapDDOSInfo]: + """ + Returns the top DDoS counts grouped by URL, User-Agent or IP + + Args: + domain_id: The domain ID + + group_by: The identity of the requests to group by + + start: Filter data items starting from a specified date in ISO 8601 format + + end: Filter data items up to a specified end date in ISO 8601 format. If not + provided, defaults to the current date and time. + + limit: Number of items to return + + offset: Number of items to skip + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/ddos-info", + page=SyncOffsetPage[WaapDDOSInfo], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "group_by": group_by, + "start": start, + "end": end, + "limit": limit, + "offset": offset, + }, + statistic_get_ddos_info_params.StatisticGetDDOSInfoParams, + ), + ), + model=WaapDDOSInfo, + ) + + def get_events_aggregated( + self, + domain_id: int, + *, + start: str, + action: Optional[List[Literal["allow", "block", "captcha", "handshake"]]] | Omit = omit, + end: Optional[str] | Omit = omit, + ip: Optional[SequenceNotStr[str]] | Omit = omit, + reference_id: Optional[SequenceNotStr[str]] | Omit = omit, + result: Optional[List[Literal["passed", "blocked", "monitored", "allowed"]]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapEventStatistics: + """ + Retrieve an domain's event statistics + + Args: + domain_id: The domain ID + + start: Filter data items starting from a specified date in ISO 8601 format + + action: A list of action names to filter on. + + end: Filter data items up to a specified end date in ISO 8601 format. If not + provided, defaults to the current date and time. + + ip: A list of IPs to filter event statistics. + + reference_id: A list of reference IDs to filter event statistics. + + result: A list of results to filter event statistics. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/waap/v1/domains/{domain_id}/stats", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start": start, + "action": action, + "end": end, + "ip": ip, + "reference_id": reference_id, + "result": result, + }, + statistic_get_events_aggregated_params.StatisticGetEventsAggregatedParams, + ), + ), + cast_to=WaapEventStatistics, + ) + + def get_request_details( + self, + request_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapRequestDetails: + """ + Retrieves all the available information for a request that matches a given + request id + + Args: + domain_id: The domain ID + + request_id: The request ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not request_id: + raise ValueError(f"Expected a non-empty value for `request_id` but received {request_id!r}") + return self._get( + f"/waap/v1/domains/{domain_id}/requests/{request_id}/details", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapRequestDetails, + ) + + @typing_extensions.deprecated("deprecated") + def get_requests_series( + self, + domain_id: int, + *, + start: str, + actions: List[Literal["allow", "block", "captcha", "handshake"]] | Omit = omit, + countries: SequenceNotStr[str] | Omit = omit, + end: Optional[str] | Omit = omit, + ip: str | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + ordering: str | Omit = omit, + reference_id: str | Omit = omit, + security_rule_name: str | Omit = omit, + status_code: int | Omit = omit, + traffic_types: List[ + Literal[ + "policy_allowed", + "policy_blocked", + "custom_rule_allowed", + "custom_blocked", + "legit_requests", + "sanctioned", + "dynamic", + "api", + "static", + "ajax", + "redirects", + "monitor", + "err_40x", + "err_50x", + "passed_to_origin", + "timeout", + "other", + "ddos", + "legit", + "monitored", + ] + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapRequestSummary]: + """Retrieve a domain's requests data. + + Deprecated. Use + [GET /v1/analytics/requests](/docs/api-reference/waap/analytics/get-request-log-data) + instead. + + Args: + domain_id: The domain ID + + start: Filter data items starting from a specified date in ISO 8601 format + + actions: Filter the response by actions. + + countries: Filter the response by country codes in ISO 3166-1 alpha-2 format. + + end: Filter data items up to a specified end date in ISO 8601 format. If not + provided, defaults to the current date and time. + + ip: Filter the response by IP. + + limit: Number of items to return + + offset: Number of items to skip + + ordering: Sort the response by given field. + + reference_id: Filter the response by reference ID. + + security_rule_name: Filter the response by security rule name. + + status_code: Filter the response by response code. + + traffic_types: Filter the response by traffic types. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/requests", + page=SyncOffsetPage[WaapRequestSummary], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start": start, + "actions": actions, + "countries": countries, + "end": end, + "ip": ip, + "limit": limit, + "offset": offset, + "ordering": ordering, + "reference_id": reference_id, + "security_rule_name": security_rule_name, + "status_code": status_code, + "traffic_types": traffic_types, + }, + statistic_get_requests_series_params.StatisticGetRequestsSeriesParams, + ), + ), + model=WaapRequestSummary, + ) + + @typing_extensions.deprecated("deprecated") + def get_traffic_series( + self, + domain_id: int, + *, + resolution: Literal["daily", "hourly", "minutely"], + start: str, + end: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StatisticGetTrafficSeriesResponse: + """Deprecated. + + Use + [GET /v1/analytics/traffic](/docs/api-reference/waap/analytics/get-traffic-data) + instead. + + Args: + domain_id: The domain ID + + resolution: Specifies the granularity of the result data. + + start: Filter data items starting from a specified date in ISO 8601 format + + end: Filter data items up to a specified end date in ISO 8601 format. If not + provided, defaults to the current date and time. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/waap/v1/domains/{domain_id}/traffic", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "resolution": resolution, + "start": start, + "end": end, + }, + statistic_get_traffic_series_params.StatisticGetTrafficSeriesParams, + ), + ), + cast_to=StatisticGetTrafficSeriesResponse, + ) + + +class AsyncStatisticsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncStatisticsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncStatisticsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncStatisticsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncStatisticsResourceWithStreamingResponse(self) + + def get_ddos_attacks( + self, + domain_id: int, + *, + end_time: Union[str, datetime, None] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + ordering: Literal["start_time", "-start_time", "end_time", "-end_time"] | Omit = omit, + start_time: Union[str, datetime, None] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapDDOSAttack, AsyncOffsetPage[WaapDDOSAttack]]: + """ + Retrieve a domain's DDoS attacks + + Args: + domain_id: The domain ID + + end_time: Filter attacks up to a specified end date in ISO 8601 format + + limit: Number of items to return + + offset: Number of items to skip + + ordering: Sort the response by given field. + + start_time: Filter attacks starting from a specified date in ISO 8601 format + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/ddos-attacks", + page=AsyncOffsetPage[WaapDDOSAttack], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "end_time": end_time, + "limit": limit, + "offset": offset, + "ordering": ordering, + "start_time": start_time, + }, + statistic_get_ddos_attacks_params.StatisticGetDDOSAttacksParams, + ), + ), + model=WaapDDOSAttack, + ) + + def get_ddos_info( + self, + domain_id: int, + *, + group_by: Literal["URL", "User-Agent", "IP"], + start: str, + end: Optional[str] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapDDOSInfo, AsyncOffsetPage[WaapDDOSInfo]]: + """ + Returns the top DDoS counts grouped by URL, User-Agent or IP + + Args: + domain_id: The domain ID + + group_by: The identity of the requests to group by + + start: Filter data items starting from a specified date in ISO 8601 format + + end: Filter data items up to a specified end date in ISO 8601 format. If not + provided, defaults to the current date and time. + + limit: Number of items to return + + offset: Number of items to skip + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/ddos-info", + page=AsyncOffsetPage[WaapDDOSInfo], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "group_by": group_by, + "start": start, + "end": end, + "limit": limit, + "offset": offset, + }, + statistic_get_ddos_info_params.StatisticGetDDOSInfoParams, + ), + ), + model=WaapDDOSInfo, + ) + + async def get_events_aggregated( + self, + domain_id: int, + *, + start: str, + action: Optional[List[Literal["allow", "block", "captcha", "handshake"]]] | Omit = omit, + end: Optional[str] | Omit = omit, + ip: Optional[SequenceNotStr[str]] | Omit = omit, + reference_id: Optional[SequenceNotStr[str]] | Omit = omit, + result: Optional[List[Literal["passed", "blocked", "monitored", "allowed"]]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapEventStatistics: + """ + Retrieve an domain's event statistics + + Args: + domain_id: The domain ID + + start: Filter data items starting from a specified date in ISO 8601 format + + action: A list of action names to filter on. + + end: Filter data items up to a specified end date in ISO 8601 format. If not + provided, defaults to the current date and time. + + ip: A list of IPs to filter event statistics. + + reference_id: A list of reference IDs to filter event statistics. + + result: A list of results to filter event statistics. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/waap/v1/domains/{domain_id}/stats", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "start": start, + "action": action, + "end": end, + "ip": ip, + "reference_id": reference_id, + "result": result, + }, + statistic_get_events_aggregated_params.StatisticGetEventsAggregatedParams, + ), + ), + cast_to=WaapEventStatistics, + ) + + async def get_request_details( + self, + request_id: str, + *, + domain_id: int, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapRequestDetails: + """ + Retrieves all the available information for a request that matches a given + request id + + Args: + domain_id: The domain ID + + request_id: The request ID + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not request_id: + raise ValueError(f"Expected a non-empty value for `request_id` but received {request_id!r}") + return await self._get( + f"/waap/v1/domains/{domain_id}/requests/{request_id}/details", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapRequestDetails, + ) + + @typing_extensions.deprecated("deprecated") + def get_requests_series( + self, + domain_id: int, + *, + start: str, + actions: List[Literal["allow", "block", "captcha", "handshake"]] | Omit = omit, + countries: SequenceNotStr[str] | Omit = omit, + end: Optional[str] | Omit = omit, + ip: str | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + ordering: str | Omit = omit, + reference_id: str | Omit = omit, + security_rule_name: str | Omit = omit, + status_code: int | Omit = omit, + traffic_types: List[ + Literal[ + "policy_allowed", + "policy_blocked", + "custom_rule_allowed", + "custom_blocked", + "legit_requests", + "sanctioned", + "dynamic", + "api", + "static", + "ajax", + "redirects", + "monitor", + "err_40x", + "err_50x", + "passed_to_origin", + "timeout", + "other", + "ddos", + "legit", + "monitored", + ] + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapRequestSummary, AsyncOffsetPage[WaapRequestSummary]]: + """Retrieve a domain's requests data. + + Deprecated. Use + [GET /v1/analytics/requests](/docs/api-reference/waap/analytics/get-request-log-data) + instead. + + Args: + domain_id: The domain ID + + start: Filter data items starting from a specified date in ISO 8601 format + + actions: Filter the response by actions. + + countries: Filter the response by country codes in ISO 3166-1 alpha-2 format. + + end: Filter data items up to a specified end date in ISO 8601 format. If not + provided, defaults to the current date and time. + + ip: Filter the response by IP. + + limit: Number of items to return + + offset: Number of items to skip + + ordering: Sort the response by given field. + + reference_id: Filter the response by reference ID. + + security_rule_name: Filter the response by security rule name. + + status_code: Filter the response by response code. + + traffic_types: Filter the response by traffic types. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + f"/waap/v1/domains/{domain_id}/requests", + page=AsyncOffsetPage[WaapRequestSummary], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "start": start, + "actions": actions, + "countries": countries, + "end": end, + "ip": ip, + "limit": limit, + "offset": offset, + "ordering": ordering, + "reference_id": reference_id, + "security_rule_name": security_rule_name, + "status_code": status_code, + "traffic_types": traffic_types, + }, + statistic_get_requests_series_params.StatisticGetRequestsSeriesParams, + ), + ), + model=WaapRequestSummary, + ) + + @typing_extensions.deprecated("deprecated") + async def get_traffic_series( + self, + domain_id: int, + *, + resolution: Literal["daily", "hourly", "minutely"], + start: str, + end: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> StatisticGetTrafficSeriesResponse: + """Deprecated. + + Use + [GET /v1/analytics/traffic](/docs/api-reference/waap/analytics/get-traffic-data) + instead. + + Args: + domain_id: The domain ID + + resolution: Specifies the granularity of the result data. + + start: Filter data items starting from a specified date in ISO 8601 format + + end: Filter data items up to a specified end date in ISO 8601 format. If not + provided, defaults to the current date and time. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/waap/v1/domains/{domain_id}/traffic", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "resolution": resolution, + "start": start, + "end": end, + }, + statistic_get_traffic_series_params.StatisticGetTrafficSeriesParams, + ), + ), + cast_to=StatisticGetTrafficSeriesResponse, + ) + + +class StatisticsResourceWithRawResponse: + def __init__(self, statistics: StatisticsResource) -> None: + self._statistics = statistics + + self.get_ddos_attacks = to_raw_response_wrapper( + statistics.get_ddos_attacks, + ) + self.get_ddos_info = to_raw_response_wrapper( + statistics.get_ddos_info, + ) + self.get_events_aggregated = to_raw_response_wrapper( + statistics.get_events_aggregated, + ) + self.get_request_details = to_raw_response_wrapper( + statistics.get_request_details, + ) + self.get_requests_series = ( # pyright: ignore[reportDeprecated] + to_raw_response_wrapper( + statistics.get_requests_series, # pyright: ignore[reportDeprecated], + ) + ) + self.get_traffic_series = ( # pyright: ignore[reportDeprecated] + to_raw_response_wrapper( + statistics.get_traffic_series, # pyright: ignore[reportDeprecated], + ) + ) + + +class AsyncStatisticsResourceWithRawResponse: + def __init__(self, statistics: AsyncStatisticsResource) -> None: + self._statistics = statistics + + self.get_ddos_attacks = async_to_raw_response_wrapper( + statistics.get_ddos_attacks, + ) + self.get_ddos_info = async_to_raw_response_wrapper( + statistics.get_ddos_info, + ) + self.get_events_aggregated = async_to_raw_response_wrapper( + statistics.get_events_aggregated, + ) + self.get_request_details = async_to_raw_response_wrapper( + statistics.get_request_details, + ) + self.get_requests_series = ( # pyright: ignore[reportDeprecated] + async_to_raw_response_wrapper( + statistics.get_requests_series, # pyright: ignore[reportDeprecated], + ) + ) + self.get_traffic_series = ( # pyright: ignore[reportDeprecated] + async_to_raw_response_wrapper( + statistics.get_traffic_series, # pyright: ignore[reportDeprecated], + ) + ) + + +class StatisticsResourceWithStreamingResponse: + def __init__(self, statistics: StatisticsResource) -> None: + self._statistics = statistics + + self.get_ddos_attacks = to_streamed_response_wrapper( + statistics.get_ddos_attacks, + ) + self.get_ddos_info = to_streamed_response_wrapper( + statistics.get_ddos_info, + ) + self.get_events_aggregated = to_streamed_response_wrapper( + statistics.get_events_aggregated, + ) + self.get_request_details = to_streamed_response_wrapper( + statistics.get_request_details, + ) + self.get_requests_series = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + statistics.get_requests_series, # pyright: ignore[reportDeprecated], + ) + ) + self.get_traffic_series = ( # pyright: ignore[reportDeprecated] + to_streamed_response_wrapper( + statistics.get_traffic_series, # pyright: ignore[reportDeprecated], + ) + ) + + +class AsyncStatisticsResourceWithStreamingResponse: + def __init__(self, statistics: AsyncStatisticsResource) -> None: + self._statistics = statistics + + self.get_ddos_attacks = async_to_streamed_response_wrapper( + statistics.get_ddos_attacks, + ) + self.get_ddos_info = async_to_streamed_response_wrapper( + statistics.get_ddos_info, + ) + self.get_events_aggregated = async_to_streamed_response_wrapper( + statistics.get_events_aggregated, + ) + self.get_request_details = async_to_streamed_response_wrapper( + statistics.get_request_details, + ) + self.get_requests_series = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + statistics.get_requests_series, # pyright: ignore[reportDeprecated], + ) + ) + self.get_traffic_series = ( # pyright: ignore[reportDeprecated] + async_to_streamed_response_wrapper( + statistics.get_traffic_series, # pyright: ignore[reportDeprecated], + ) + ) diff --git a/src/gcore/resources/waap/insights.py b/src/gcore/resources/waap/insights.py new file mode 100644 index 00000000..c9fc4370 --- /dev/null +++ b/src/gcore/resources/waap/insights.py @@ -0,0 +1,231 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ...types.waap import insight_list_types_params +from ..._base_client import AsyncPaginator, make_request_options +from ...types.waap.waap_insight_type import WaapInsightType + +__all__ = ["InsightsResource", "AsyncInsightsResource"] + + +class InsightsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> InsightsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return InsightsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InsightsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return InsightsResourceWithStreamingResponse(self) + + def list_types( + self, + *, + insight_frequency: Optional[int] | Omit = omit, + limit: int | Omit = omit, + name: Optional[str] | Omit = omit, + offset: int | Omit = omit, + ordering: Literal["name", "-name", "slug", "-slug", "insight_frequency", "-insight_frequency"] | Omit = omit, + slug: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapInsightType]: + """ + Insight types are generalized categories that encompass various specific + occurrences of the same kind. + + Args: + insight_frequency: Filter by the frequency of the insight type + + limit: Number of items to return + + name: Filter by the name of the insight type + + offset: Number of items to skip + + ordering: Sort the response by given field. + + slug: Filter by the slug of the insight type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/waap/v1/security-insights/types", + page=SyncOffsetPage[WaapInsightType], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "insight_frequency": insight_frequency, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + "slug": slug, + }, + insight_list_types_params.InsightListTypesParams, + ), + ), + model=WaapInsightType, + ) + + +class AsyncInsightsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncInsightsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncInsightsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInsightsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncInsightsResourceWithStreamingResponse(self) + + def list_types( + self, + *, + insight_frequency: Optional[int] | Omit = omit, + limit: int | Omit = omit, + name: Optional[str] | Omit = omit, + offset: int | Omit = omit, + ordering: Literal["name", "-name", "slug", "-slug", "insight_frequency", "-insight_frequency"] | Omit = omit, + slug: Optional[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapInsightType, AsyncOffsetPage[WaapInsightType]]: + """ + Insight types are generalized categories that encompass various specific + occurrences of the same kind. + + Args: + insight_frequency: Filter by the frequency of the insight type + + limit: Number of items to return + + name: Filter by the name of the insight type + + offset: Number of items to skip + + ordering: Sort the response by given field. + + slug: Filter by the slug of the insight type + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/waap/v1/security-insights/types", + page=AsyncOffsetPage[WaapInsightType], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "insight_frequency": insight_frequency, + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + "slug": slug, + }, + insight_list_types_params.InsightListTypesParams, + ), + ), + model=WaapInsightType, + ) + + +class InsightsResourceWithRawResponse: + def __init__(self, insights: InsightsResource) -> None: + self._insights = insights + + self.list_types = to_raw_response_wrapper( + insights.list_types, + ) + + +class AsyncInsightsResourceWithRawResponse: + def __init__(self, insights: AsyncInsightsResource) -> None: + self._insights = insights + + self.list_types = async_to_raw_response_wrapper( + insights.list_types, + ) + + +class InsightsResourceWithStreamingResponse: + def __init__(self, insights: InsightsResource) -> None: + self._insights = insights + + self.list_types = to_streamed_response_wrapper( + insights.list_types, + ) + + +class AsyncInsightsResourceWithStreamingResponse: + def __init__(self, insights: AsyncInsightsResource) -> None: + self._insights = insights + + self.list_types = async_to_streamed_response_wrapper( + insights.list_types, + ) diff --git a/src/gcore/resources/waap/ip_info/__init__.py b/src/gcore/resources/waap/ip_info/__init__.py new file mode 100644 index 00000000..98a9875c --- /dev/null +++ b/src/gcore/resources/waap/ip_info/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .ip_info import ( + IPInfoResource, + AsyncIPInfoResource, + IPInfoResourceWithRawResponse, + AsyncIPInfoResourceWithRawResponse, + IPInfoResourceWithStreamingResponse, + AsyncIPInfoResourceWithStreamingResponse, +) +from .metrics import ( + MetricsResource, + AsyncMetricsResource, + MetricsResourceWithRawResponse, + AsyncMetricsResourceWithRawResponse, + MetricsResourceWithStreamingResponse, + AsyncMetricsResourceWithStreamingResponse, +) + +__all__ = [ + "MetricsResource", + "AsyncMetricsResource", + "MetricsResourceWithRawResponse", + "AsyncMetricsResourceWithRawResponse", + "MetricsResourceWithStreamingResponse", + "AsyncMetricsResourceWithStreamingResponse", + "IPInfoResource", + "AsyncIPInfoResource", + "IPInfoResourceWithRawResponse", + "AsyncIPInfoResourceWithRawResponse", + "IPInfoResourceWithStreamingResponse", + "AsyncIPInfoResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/waap/ip_info/ip_info.py b/src/gcore/resources/waap/ip_info/ip_info.py new file mode 100644 index 00000000..0c0050f2 --- /dev/null +++ b/src/gcore/resources/waap/ip_info/ip_info.py @@ -0,0 +1,949 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .metrics import ( + MetricsResource, + AsyncMetricsResource, + MetricsResourceWithRawResponse, + AsyncMetricsResourceWithRawResponse, + MetricsResourceWithStreamingResponse, + AsyncMetricsResourceWithStreamingResponse, +) +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....types.waap import ( + ip_info_get_ip_info_params, + ip_info_get_top_urls_params, + ip_info_get_top_user_agents_params, + ip_info_get_blocked_requests_params, + ip_info_get_top_user_sessions_params, + ip_info_get_attack_time_series_params, + ip_info_get_ddos_attack_series_params, + ip_info_list_attacked_countries_params, +) +from ...._base_client import make_request_options +from ....types.waap.waap_ip_info import WaapIPInfo +from ....types.waap.waap_ip_ddos_info_model import WaapIPDDOSInfoModel +from ....types.waap.ip_info_get_top_urls_response import IPInfoGetTopURLsResponse +from ....types.waap.ip_info_get_top_user_agents_response import IPInfoGetTopUserAgentsResponse +from ....types.waap.ip_info_get_blocked_requests_response import IPInfoGetBlockedRequestsResponse +from ....types.waap.ip_info_get_top_user_sessions_response import IPInfoGetTopUserSessionsResponse +from ....types.waap.ip_info_get_attack_time_series_response import IPInfoGetAttackTimeSeriesResponse +from ....types.waap.ip_info_list_attacked_countries_response import IPInfoListAttackedCountriesResponse + +__all__ = ["IPInfoResource", "AsyncIPInfoResource"] + + +class IPInfoResource(SyncAPIResource): + @cached_property + def metrics(self) -> MetricsResource: + return MetricsResource(self._client) + + @cached_property + def with_raw_response(self) -> IPInfoResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return IPInfoResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> IPInfoResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return IPInfoResourceWithStreamingResponse(self) + + def get_attack_time_series( + self, + *, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPInfoGetAttackTimeSeriesResponse: + """ + Retrieve a time-series of attacks originating from a specified IP address. + + Args: + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/waap/v1/ip-info/attack-time-series", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + {"ip": ip}, ip_info_get_attack_time_series_params.IPInfoGetAttackTimeSeriesParams + ), + ), + cast_to=IPInfoGetAttackTimeSeriesResponse, + ) + + def get_blocked_requests( + self, + *, + domain_id: int, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPInfoGetBlockedRequestsResponse: + """ + Retrieve metrics, which enumerate blocked requests originating from a specific + IP to a domain, grouped by rule name and taken action. Each metric provides + insights into the request count blocked under a specific rule and the + corresponding action that was executed. + + Args: + domain_id: The identifier for a domain. When specified, the response will exclusively + contain data pertinent to the indicated domain, filtering out information from + other domains. + + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/waap/v1/ip-info/blocked-requests", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "domain_id": domain_id, + "ip": ip, + }, + ip_info_get_blocked_requests_params.IPInfoGetBlockedRequestsParams, + ), + ), + cast_to=IPInfoGetBlockedRequestsResponse, + ) + + def get_ddos_attack_series( + self, + *, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapIPDDOSInfoModel: + """ + Fetch and analyze DDoS (Distributed Denial of Service) attack metrics for a + specified IP address. The endpoint provides time-series data, enabling users to + evaluate the frequency and intensity of attacks across various time intervals, + and it returns metrics in Prometheus format to offer a systematic view of DDoS + attack patterns. + + Args: + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/waap/v1/ip-info/ddos", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + {"ip": ip}, ip_info_get_ddos_attack_series_params.IPInfoGetDDOSAttackSeriesParams + ), + ), + cast_to=WaapIPDDOSInfoModel, + ) + + def get_ip_info( + self, + *, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapIPInfo: + """ + Fetch details about a particular IP address, including WHOIS data, risk score, + and additional tags. + + Args: + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/waap/v1/ip-info/ip-info", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"ip": ip}, ip_info_get_ip_info_params.IPInfoGetIPInfoParams), + ), + cast_to=WaapIPInfo, + ) + + def get_top_urls( + self, + *, + domain_id: int, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPInfoGetTopURLsResponse: + """ + Returns a list of the top 10 URLs accessed by a specified IP address within a + specific domain. This data is vital to understand user navigation patterns, + pinpoint high-traffic pages, and facilitate more targeted enhancements or + security monitoring based on URL popularity. + + Args: + domain_id: The identifier for a domain. When specified, the response will exclusively + contain data pertinent to the indicated domain, filtering out information from + other domains. + + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/waap/v1/ip-info/top-urls", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "domain_id": domain_id, + "ip": ip, + }, + ip_info_get_top_urls_params.IPInfoGetTopURLsParams, + ), + ), + cast_to=IPInfoGetTopURLsResponse, + ) + + def get_top_user_agents( + self, + *, + domain_id: int, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPInfoGetTopUserAgentsResponse: + """ + Retrieve the top 10 user agents interacting with a specified domain, filtered by + IP. + + Args: + domain_id: The identifier for a domain. When specified, the response will exclusively + contain data pertinent to the indicated domain, filtering out information from + other domains. + + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/waap/v1/ip-info/top-user-agents", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "domain_id": domain_id, + "ip": ip, + }, + ip_info_get_top_user_agents_params.IPInfoGetTopUserAgentsParams, + ), + ), + cast_to=IPInfoGetTopUserAgentsResponse, + ) + + def get_top_user_sessions( + self, + *, + domain_id: int, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPInfoGetTopUserSessionsResponse: + """ + Obtain the top 10 user sessions interfacing with a particular domain, identified + by IP. + + Args: + domain_id: The identifier for a domain. When specified, the response will exclusively + contain data pertinent to the indicated domain, filtering out information from + other domains. + + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/waap/v1/ip-info/top-sessions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "domain_id": domain_id, + "ip": ip, + }, + ip_info_get_top_user_sessions_params.IPInfoGetTopUserSessionsParams, + ), + ), + cast_to=IPInfoGetTopUserSessionsResponse, + ) + + def list_attacked_countries( + self, + *, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPInfoListAttackedCountriesResponse: + """ + Retrieve a list of countries attacked by the specified IP address + + Args: + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/waap/v1/ip-info/attack-map", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + {"ip": ip}, ip_info_list_attacked_countries_params.IPInfoListAttackedCountriesParams + ), + ), + cast_to=IPInfoListAttackedCountriesResponse, + ) + + +class AsyncIPInfoResource(AsyncAPIResource): + @cached_property + def metrics(self) -> AsyncMetricsResource: + return AsyncMetricsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncIPInfoResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncIPInfoResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncIPInfoResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncIPInfoResourceWithStreamingResponse(self) + + async def get_attack_time_series( + self, + *, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPInfoGetAttackTimeSeriesResponse: + """ + Retrieve a time-series of attacks originating from a specified IP address. + + Args: + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/waap/v1/ip-info/attack-time-series", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"ip": ip}, ip_info_get_attack_time_series_params.IPInfoGetAttackTimeSeriesParams + ), + ), + cast_to=IPInfoGetAttackTimeSeriesResponse, + ) + + async def get_blocked_requests( + self, + *, + domain_id: int, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPInfoGetBlockedRequestsResponse: + """ + Retrieve metrics, which enumerate blocked requests originating from a specific + IP to a domain, grouped by rule name and taken action. Each metric provides + insights into the request count blocked under a specific rule and the + corresponding action that was executed. + + Args: + domain_id: The identifier for a domain. When specified, the response will exclusively + contain data pertinent to the indicated domain, filtering out information from + other domains. + + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/waap/v1/ip-info/blocked-requests", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "domain_id": domain_id, + "ip": ip, + }, + ip_info_get_blocked_requests_params.IPInfoGetBlockedRequestsParams, + ), + ), + cast_to=IPInfoGetBlockedRequestsResponse, + ) + + async def get_ddos_attack_series( + self, + *, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapIPDDOSInfoModel: + """ + Fetch and analyze DDoS (Distributed Denial of Service) attack metrics for a + specified IP address. The endpoint provides time-series data, enabling users to + evaluate the frequency and intensity of attacks across various time intervals, + and it returns metrics in Prometheus format to offer a systematic view of DDoS + attack patterns. + + Args: + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/waap/v1/ip-info/ddos", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"ip": ip}, ip_info_get_ddos_attack_series_params.IPInfoGetDDOSAttackSeriesParams + ), + ), + cast_to=WaapIPDDOSInfoModel, + ) + + async def get_ip_info( + self, + *, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapIPInfo: + """ + Fetch details about a particular IP address, including WHOIS data, risk score, + and additional tags. + + Args: + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/waap/v1/ip-info/ip-info", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"ip": ip}, ip_info_get_ip_info_params.IPInfoGetIPInfoParams), + ), + cast_to=WaapIPInfo, + ) + + async def get_top_urls( + self, + *, + domain_id: int, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPInfoGetTopURLsResponse: + """ + Returns a list of the top 10 URLs accessed by a specified IP address within a + specific domain. This data is vital to understand user navigation patterns, + pinpoint high-traffic pages, and facilitate more targeted enhancements or + security monitoring based on URL popularity. + + Args: + domain_id: The identifier for a domain. When specified, the response will exclusively + contain data pertinent to the indicated domain, filtering out information from + other domains. + + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/waap/v1/ip-info/top-urls", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "domain_id": domain_id, + "ip": ip, + }, + ip_info_get_top_urls_params.IPInfoGetTopURLsParams, + ), + ), + cast_to=IPInfoGetTopURLsResponse, + ) + + async def get_top_user_agents( + self, + *, + domain_id: int, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPInfoGetTopUserAgentsResponse: + """ + Retrieve the top 10 user agents interacting with a specified domain, filtered by + IP. + + Args: + domain_id: The identifier for a domain. When specified, the response will exclusively + contain data pertinent to the indicated domain, filtering out information from + other domains. + + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/waap/v1/ip-info/top-user-agents", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "domain_id": domain_id, + "ip": ip, + }, + ip_info_get_top_user_agents_params.IPInfoGetTopUserAgentsParams, + ), + ), + cast_to=IPInfoGetTopUserAgentsResponse, + ) + + async def get_top_user_sessions( + self, + *, + domain_id: int, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPInfoGetTopUserSessionsResponse: + """ + Obtain the top 10 user sessions interfacing with a particular domain, identified + by IP. + + Args: + domain_id: The identifier for a domain. When specified, the response will exclusively + contain data pertinent to the indicated domain, filtering out information from + other domains. + + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/waap/v1/ip-info/top-sessions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "domain_id": domain_id, + "ip": ip, + }, + ip_info_get_top_user_sessions_params.IPInfoGetTopUserSessionsParams, + ), + ), + cast_to=IPInfoGetTopUserSessionsResponse, + ) + + async def list_attacked_countries( + self, + *, + ip: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> IPInfoListAttackedCountriesResponse: + """ + Retrieve a list of countries attacked by the specified IP address + + Args: + ip: The IP address to check + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/waap/v1/ip-info/attack-map", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"ip": ip}, ip_info_list_attacked_countries_params.IPInfoListAttackedCountriesParams + ), + ), + cast_to=IPInfoListAttackedCountriesResponse, + ) + + +class IPInfoResourceWithRawResponse: + def __init__(self, ip_info: IPInfoResource) -> None: + self._ip_info = ip_info + + self.get_attack_time_series = to_raw_response_wrapper( + ip_info.get_attack_time_series, + ) + self.get_blocked_requests = to_raw_response_wrapper( + ip_info.get_blocked_requests, + ) + self.get_ddos_attack_series = to_raw_response_wrapper( + ip_info.get_ddos_attack_series, + ) + self.get_ip_info = to_raw_response_wrapper( + ip_info.get_ip_info, + ) + self.get_top_urls = to_raw_response_wrapper( + ip_info.get_top_urls, + ) + self.get_top_user_agents = to_raw_response_wrapper( + ip_info.get_top_user_agents, + ) + self.get_top_user_sessions = to_raw_response_wrapper( + ip_info.get_top_user_sessions, + ) + self.list_attacked_countries = to_raw_response_wrapper( + ip_info.list_attacked_countries, + ) + + @cached_property + def metrics(self) -> MetricsResourceWithRawResponse: + return MetricsResourceWithRawResponse(self._ip_info.metrics) + + +class AsyncIPInfoResourceWithRawResponse: + def __init__(self, ip_info: AsyncIPInfoResource) -> None: + self._ip_info = ip_info + + self.get_attack_time_series = async_to_raw_response_wrapper( + ip_info.get_attack_time_series, + ) + self.get_blocked_requests = async_to_raw_response_wrapper( + ip_info.get_blocked_requests, + ) + self.get_ddos_attack_series = async_to_raw_response_wrapper( + ip_info.get_ddos_attack_series, + ) + self.get_ip_info = async_to_raw_response_wrapper( + ip_info.get_ip_info, + ) + self.get_top_urls = async_to_raw_response_wrapper( + ip_info.get_top_urls, + ) + self.get_top_user_agents = async_to_raw_response_wrapper( + ip_info.get_top_user_agents, + ) + self.get_top_user_sessions = async_to_raw_response_wrapper( + ip_info.get_top_user_sessions, + ) + self.list_attacked_countries = async_to_raw_response_wrapper( + ip_info.list_attacked_countries, + ) + + @cached_property + def metrics(self) -> AsyncMetricsResourceWithRawResponse: + return AsyncMetricsResourceWithRawResponse(self._ip_info.metrics) + + +class IPInfoResourceWithStreamingResponse: + def __init__(self, ip_info: IPInfoResource) -> None: + self._ip_info = ip_info + + self.get_attack_time_series = to_streamed_response_wrapper( + ip_info.get_attack_time_series, + ) + self.get_blocked_requests = to_streamed_response_wrapper( + ip_info.get_blocked_requests, + ) + self.get_ddos_attack_series = to_streamed_response_wrapper( + ip_info.get_ddos_attack_series, + ) + self.get_ip_info = to_streamed_response_wrapper( + ip_info.get_ip_info, + ) + self.get_top_urls = to_streamed_response_wrapper( + ip_info.get_top_urls, + ) + self.get_top_user_agents = to_streamed_response_wrapper( + ip_info.get_top_user_agents, + ) + self.get_top_user_sessions = to_streamed_response_wrapper( + ip_info.get_top_user_sessions, + ) + self.list_attacked_countries = to_streamed_response_wrapper( + ip_info.list_attacked_countries, + ) + + @cached_property + def metrics(self) -> MetricsResourceWithStreamingResponse: + return MetricsResourceWithStreamingResponse(self._ip_info.metrics) + + +class AsyncIPInfoResourceWithStreamingResponse: + def __init__(self, ip_info: AsyncIPInfoResource) -> None: + self._ip_info = ip_info + + self.get_attack_time_series = async_to_streamed_response_wrapper( + ip_info.get_attack_time_series, + ) + self.get_blocked_requests = async_to_streamed_response_wrapper( + ip_info.get_blocked_requests, + ) + self.get_ddos_attack_series = async_to_streamed_response_wrapper( + ip_info.get_ddos_attack_series, + ) + self.get_ip_info = async_to_streamed_response_wrapper( + ip_info.get_ip_info, + ) + self.get_top_urls = async_to_streamed_response_wrapper( + ip_info.get_top_urls, + ) + self.get_top_user_agents = async_to_streamed_response_wrapper( + ip_info.get_top_user_agents, + ) + self.get_top_user_sessions = async_to_streamed_response_wrapper( + ip_info.get_top_user_sessions, + ) + self.list_attacked_countries = async_to_streamed_response_wrapper( + ip_info.list_attacked_countries, + ) + + @cached_property + def metrics(self) -> AsyncMetricsResourceWithStreamingResponse: + return AsyncMetricsResourceWithStreamingResponse(self._ip_info.metrics) diff --git a/src/gcore/resources/waap/ip_info/metrics.py b/src/gcore/resources/waap/ip_info/metrics.py new file mode 100644 index 00000000..dd60d037 --- /dev/null +++ b/src/gcore/resources/waap/ip_info/metrics.py @@ -0,0 +1,203 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.waap.ip_info import metric_list_params +from ....types.waap.ip_info.waap_ip_info_counts import WaapIPInfoCounts + +__all__ = ["MetricsResource", "AsyncMetricsResource"] + + +class MetricsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> MetricsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return MetricsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MetricsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return MetricsResourceWithStreamingResponse(self) + + def list( + self, + *, + ip: str, + domain_id: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapIPInfoCounts: + """ + Retrieve metrics encompassing the counts of total requests, blocked requests and + unique sessions associated with a specified IP address. Metrics provide a + statistical overview, aiding in analyzing the interaction and access patterns of + the IP address in context. + + Args: + ip: The IP address to check + + domain_id: The identifier for a domain. When specified, the response will exclusively + contain data pertinent to the indicated domain, filtering out information from + other domains. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/waap/v1/ip-info/counts", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "ip": ip, + "domain_id": domain_id, + }, + metric_list_params.MetricListParams, + ), + ), + cast_to=WaapIPInfoCounts, + ) + + +class AsyncMetricsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncMetricsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncMetricsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMetricsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncMetricsResourceWithStreamingResponse(self) + + async def list( + self, + *, + ip: str, + domain_id: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapIPInfoCounts: + """ + Retrieve metrics encompassing the counts of total requests, blocked requests and + unique sessions associated with a specified IP address. Metrics provide a + statistical overview, aiding in analyzing the interaction and access patterns of + the IP address in context. + + Args: + ip: The IP address to check + + domain_id: The identifier for a domain. When specified, the response will exclusively + contain data pertinent to the indicated domain, filtering out information from + other domains. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/waap/v1/ip-info/counts", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "ip": ip, + "domain_id": domain_id, + }, + metric_list_params.MetricListParams, + ), + ), + cast_to=WaapIPInfoCounts, + ) + + +class MetricsResourceWithRawResponse: + def __init__(self, metrics: MetricsResource) -> None: + self._metrics = metrics + + self.list = to_raw_response_wrapper( + metrics.list, + ) + + +class AsyncMetricsResourceWithRawResponse: + def __init__(self, metrics: AsyncMetricsResource) -> None: + self._metrics = metrics + + self.list = async_to_raw_response_wrapper( + metrics.list, + ) + + +class MetricsResourceWithStreamingResponse: + def __init__(self, metrics: MetricsResource) -> None: + self._metrics = metrics + + self.list = to_streamed_response_wrapper( + metrics.list, + ) + + +class AsyncMetricsResourceWithStreamingResponse: + def __init__(self, metrics: AsyncMetricsResource) -> None: + self._metrics = metrics + + self.list = async_to_streamed_response_wrapper( + metrics.list, + ) diff --git a/src/gcore/resources/waap/organizations.py b/src/gcore/resources/waap/organizations.py new file mode 100644 index 00000000..07a8bc66 --- /dev/null +++ b/src/gcore/resources/waap/organizations.py @@ -0,0 +1,217 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ...types.waap import organization_list_params +from ..._base_client import AsyncPaginator, make_request_options +from ...types.waap.waap_organization import WaapOrganization + +__all__ = ["OrganizationsResource", "AsyncOrganizationsResource"] + + +class OrganizationsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> OrganizationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return OrganizationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> OrganizationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return OrganizationsResourceWithStreamingResponse(self) + + def list( + self, + *, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Optional[Literal["name", "id", "-name", "-id"]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapOrganization]: + """ + This endpoint retrieves a list of network organizations that own IP ranges as + identified by the Whois service.It supports pagination, filtering based on + various parameters, and ordering of results. + + Args: + limit: Number of items to return + + name: Filter organizations by their name. Supports '\\**' as a wildcard character. + + offset: Number of items to skip + + ordering: Determine the field to order results by + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/waap/v1/organizations", + page=SyncOffsetPage[WaapOrganization], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + }, + organization_list_params.OrganizationListParams, + ), + ), + model=WaapOrganization, + ) + + +class AsyncOrganizationsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncOrganizationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncOrganizationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncOrganizationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncOrganizationsResourceWithStreamingResponse(self) + + def list( + self, + *, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Optional[Literal["name", "id", "-name", "-id"]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapOrganization, AsyncOffsetPage[WaapOrganization]]: + """ + This endpoint retrieves a list of network organizations that own IP ranges as + identified by the Whois service.It supports pagination, filtering based on + various parameters, and ordering of results. + + Args: + limit: Number of items to return + + name: Filter organizations by their name. Supports '\\**' as a wildcard character. + + offset: Number of items to skip + + ordering: Determine the field to order results by + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/waap/v1/organizations", + page=AsyncOffsetPage[WaapOrganization], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + }, + organization_list_params.OrganizationListParams, + ), + ), + model=WaapOrganization, + ) + + +class OrganizationsResourceWithRawResponse: + def __init__(self, organizations: OrganizationsResource) -> None: + self._organizations = organizations + + self.list = to_raw_response_wrapper( + organizations.list, + ) + + +class AsyncOrganizationsResourceWithRawResponse: + def __init__(self, organizations: AsyncOrganizationsResource) -> None: + self._organizations = organizations + + self.list = async_to_raw_response_wrapper( + organizations.list, + ) + + +class OrganizationsResourceWithStreamingResponse: + def __init__(self, organizations: OrganizationsResource) -> None: + self._organizations = organizations + + self.list = to_streamed_response_wrapper( + organizations.list, + ) + + +class AsyncOrganizationsResourceWithStreamingResponse: + def __init__(self, organizations: AsyncOrganizationsResource) -> None: + self._organizations = organizations + + self.list = async_to_streamed_response_wrapper( + organizations.list, + ) diff --git a/src/gcore/resources/waap/statistics.py b/src/gcore/resources/waap/statistics.py new file mode 100644 index 00000000..e383f236 --- /dev/null +++ b/src/gcore/resources/waap/statistics.py @@ -0,0 +1,225 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.waap import statistic_get_usage_series_params +from ..._base_client import make_request_options +from ...types.waap.waap_statistics_series import WaapStatisticsSeries + +__all__ = ["StatisticsResource", "AsyncStatisticsResource"] + + +class StatisticsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> StatisticsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return StatisticsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> StatisticsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return StatisticsResourceWithStreamingResponse(self) + + def get_usage_series( + self, + *, + from_: Union[str, datetime], + granularity: Literal["1h", "1d"], + metrics: List[Literal["total_bytes", "total_requests"]], + to: Union[str, datetime], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapStatisticsSeries: + """Retrieve statistics data as a time series. + + The `from` and `to` parameters are + rounded down and up according to the `granularity`. This means that if the + `granularity` is set to `1h`, the `from` and `to` parameters will be rounded + down and up to the nearest hour, respectively. If the `granularity` is set to + `1d`, the `from` and `to` parameters will be rounded down and up to the nearest + day, respectively. The response will include explicit 0 values for any missing + data points. + + Args: + from_: Beginning of the requested time period (ISO 8601 format, UTC) + + granularity: Duration of the time blocks into which the data will be divided. + + metrics: List of metric types to retrieve statistics for. + + to: End of the requested time period (ISO 8601 format, UTC) + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/waap/v1/statistics/series", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "from_": from_, + "granularity": granularity, + "metrics": metrics, + "to": to, + }, + statistic_get_usage_series_params.StatisticGetUsageSeriesParams, + ), + ), + cast_to=WaapStatisticsSeries, + ) + + +class AsyncStatisticsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncStatisticsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncStatisticsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncStatisticsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncStatisticsResourceWithStreamingResponse(self) + + async def get_usage_series( + self, + *, + from_: Union[str, datetime], + granularity: Literal["1h", "1d"], + metrics: List[Literal["total_bytes", "total_requests"]], + to: Union[str, datetime], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapStatisticsSeries: + """Retrieve statistics data as a time series. + + The `from` and `to` parameters are + rounded down and up according to the `granularity`. This means that if the + `granularity` is set to `1h`, the `from` and `to` parameters will be rounded + down and up to the nearest hour, respectively. If the `granularity` is set to + `1d`, the `from` and `to` parameters will be rounded down and up to the nearest + day, respectively. The response will include explicit 0 values for any missing + data points. + + Args: + from_: Beginning of the requested time period (ISO 8601 format, UTC) + + granularity: Duration of the time blocks into which the data will be divided. + + metrics: List of metric types to retrieve statistics for. + + to: End of the requested time period (ISO 8601 format, UTC) + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/waap/v1/statistics/series", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "from_": from_, + "granularity": granularity, + "metrics": metrics, + "to": to, + }, + statistic_get_usage_series_params.StatisticGetUsageSeriesParams, + ), + ), + cast_to=WaapStatisticsSeries, + ) + + +class StatisticsResourceWithRawResponse: + def __init__(self, statistics: StatisticsResource) -> None: + self._statistics = statistics + + self.get_usage_series = to_raw_response_wrapper( + statistics.get_usage_series, + ) + + +class AsyncStatisticsResourceWithRawResponse: + def __init__(self, statistics: AsyncStatisticsResource) -> None: + self._statistics = statistics + + self.get_usage_series = async_to_raw_response_wrapper( + statistics.get_usage_series, + ) + + +class StatisticsResourceWithStreamingResponse: + def __init__(self, statistics: StatisticsResource) -> None: + self._statistics = statistics + + self.get_usage_series = to_streamed_response_wrapper( + statistics.get_usage_series, + ) + + +class AsyncStatisticsResourceWithStreamingResponse: + def __init__(self, statistics: AsyncStatisticsResource) -> None: + self._statistics = statistics + + self.get_usage_series = async_to_streamed_response_wrapper( + statistics.get_usage_series, + ) diff --git a/src/gcore/resources/waap/tags.py b/src/gcore/resources/waap/tags.py new file mode 100644 index 00000000..879f3f47 --- /dev/null +++ b/src/gcore/resources/waap/tags.py @@ -0,0 +1,233 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPage, AsyncOffsetPage +from ...types.waap import tag_list_params +from ..._base_client import AsyncPaginator, make_request_options +from ...types.waap.waap_tag import WaapTag + +__all__ = ["TagsResource", "AsyncTagsResource"] + + +class TagsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> TagsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return TagsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TagsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return TagsResourceWithStreamingResponse(self) + + def list( + self, + *, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Optional[Literal["name", "readable_name", "reserved", "-name", "-readable_name", "-reserved"]] + | Omit = omit, + readable_name: str | Omit = omit, + reserved: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPage[WaapTag]: + """ + Tags are shortcuts for the rules used in WAAP policies for the creation of more + complex WAAP rules + + Args: + limit: Number of items to return + + name: Filter tags by their name. Supports '\\**' as a wildcard character. + + offset: Number of items to skip + + ordering: Determine the field to order results by + + readable_name: Filter tags by their readable name. Supports '\\**' as a wildcard character. + + reserved: Filter to include only reserved tags. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/waap/v1/tags", + page=SyncOffsetPage[WaapTag], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + "readable_name": readable_name, + "reserved": reserved, + }, + tag_list_params.TagListParams, + ), + ), + model=WaapTag, + ) + + +class AsyncTagsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncTagsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncTagsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTagsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncTagsResourceWithStreamingResponse(self) + + def list( + self, + *, + limit: int | Omit = omit, + name: str | Omit = omit, + offset: int | Omit = omit, + ordering: Optional[Literal["name", "readable_name", "reserved", "-name", "-readable_name", "-reserved"]] + | Omit = omit, + readable_name: str | Omit = omit, + reserved: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[WaapTag, AsyncOffsetPage[WaapTag]]: + """ + Tags are shortcuts for the rules used in WAAP policies for the creation of more + complex WAAP rules + + Args: + limit: Number of items to return + + name: Filter tags by their name. Supports '\\**' as a wildcard character. + + offset: Number of items to skip + + ordering: Determine the field to order results by + + readable_name: Filter tags by their readable name. Supports '\\**' as a wildcard character. + + reserved: Filter to include only reserved tags. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/waap/v1/tags", + page=AsyncOffsetPage[WaapTag], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "name": name, + "offset": offset, + "ordering": ordering, + "readable_name": readable_name, + "reserved": reserved, + }, + tag_list_params.TagListParams, + ), + ), + model=WaapTag, + ) + + +class TagsResourceWithRawResponse: + def __init__(self, tags: TagsResource) -> None: + self._tags = tags + + self.list = to_raw_response_wrapper( + tags.list, + ) + + +class AsyncTagsResourceWithRawResponse: + def __init__(self, tags: AsyncTagsResource) -> None: + self._tags = tags + + self.list = async_to_raw_response_wrapper( + tags.list, + ) + + +class TagsResourceWithStreamingResponse: + def __init__(self, tags: TagsResource) -> None: + self._tags = tags + + self.list = to_streamed_response_wrapper( + tags.list, + ) + + +class AsyncTagsResourceWithStreamingResponse: + def __init__(self, tags: AsyncTagsResource) -> None: + self._tags = tags + + self.list = async_to_streamed_response_wrapper( + tags.list, + ) diff --git a/src/gcore/resources/waap/waap.py b/src/gcore/resources/waap/waap.py new file mode 100644 index 00000000..d5509b5f --- /dev/null +++ b/src/gcore/resources/waap/waap.py @@ -0,0 +1,391 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .tags import ( + TagsResource, + AsyncTagsResource, + TagsResourceWithRawResponse, + AsyncTagsResourceWithRawResponse, + TagsResourceWithStreamingResponse, + AsyncTagsResourceWithStreamingResponse, +) +from ..._types import Body, Query, Headers, NotGiven, not_given +from .insights import ( + InsightsResource, + AsyncInsightsResource, + InsightsResourceWithRawResponse, + AsyncInsightsResourceWithRawResponse, + InsightsResourceWithStreamingResponse, + AsyncInsightsResourceWithStreamingResponse, +) +from ..._compat import cached_property +from .statistics import ( + StatisticsResource, + AsyncStatisticsResource, + StatisticsResourceWithRawResponse, + AsyncStatisticsResourceWithRawResponse, + StatisticsResourceWithStreamingResponse, + AsyncStatisticsResourceWithStreamingResponse, +) +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .organizations import ( + OrganizationsResource, + AsyncOrganizationsResource, + OrganizationsResourceWithRawResponse, + AsyncOrganizationsResourceWithRawResponse, + OrganizationsResourceWithStreamingResponse, + AsyncOrganizationsResourceWithStreamingResponse, +) +from ..._base_client import make_request_options +from .advanced_rules import ( + AdvancedRulesResource, + AsyncAdvancedRulesResource, + AdvancedRulesResourceWithRawResponse, + AsyncAdvancedRulesResourceWithRawResponse, + AdvancedRulesResourceWithStreamingResponse, + AsyncAdvancedRulesResourceWithStreamingResponse, +) +from .domains.domains import ( + DomainsResource, + AsyncDomainsResource, + DomainsResourceWithRawResponse, + AsyncDomainsResourceWithRawResponse, + DomainsResourceWithStreamingResponse, + AsyncDomainsResourceWithStreamingResponse, +) +from .ip_info.ip_info import ( + IPInfoResource, + AsyncIPInfoResource, + IPInfoResourceWithRawResponse, + AsyncIPInfoResourceWithRawResponse, + IPInfoResourceWithStreamingResponse, + AsyncIPInfoResourceWithStreamingResponse, +) +from .custom_page_sets import ( + CustomPageSetsResource, + AsyncCustomPageSetsResource, + CustomPageSetsResourceWithRawResponse, + AsyncCustomPageSetsResourceWithRawResponse, + CustomPageSetsResourceWithStreamingResponse, + AsyncCustomPageSetsResourceWithStreamingResponse, +) +from ...types.waap.waap_get_account_overview_response import WaapGetAccountOverviewResponse + +__all__ = ["WaapResource", "AsyncWaapResource"] + + +class WaapResource(SyncAPIResource): + @cached_property + def statistics(self) -> StatisticsResource: + return StatisticsResource(self._client) + + @cached_property + def domains(self) -> DomainsResource: + return DomainsResource(self._client) + + @cached_property + def custom_page_sets(self) -> CustomPageSetsResource: + return CustomPageSetsResource(self._client) + + @cached_property + def advanced_rules(self) -> AdvancedRulesResource: + return AdvancedRulesResource(self._client) + + @cached_property + def tags(self) -> TagsResource: + return TagsResource(self._client) + + @cached_property + def organizations(self) -> OrganizationsResource: + return OrganizationsResource(self._client) + + @cached_property + def insights(self) -> InsightsResource: + return InsightsResource(self._client) + + @cached_property + def ip_info(self) -> IPInfoResource: + return IPInfoResource(self._client) + + @cached_property + def with_raw_response(self) -> WaapResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return WaapResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> WaapResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return WaapResourceWithStreamingResponse(self) + + def get_account_overview( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapGetAccountOverviewResponse: + """Get information about WAAP service for the client""" + return self._get( + "/waap/v1/clients/me", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapGetAccountOverviewResponse, + ) + + +class AsyncWaapResource(AsyncAPIResource): + @cached_property + def statistics(self) -> AsyncStatisticsResource: + return AsyncStatisticsResource(self._client) + + @cached_property + def domains(self) -> AsyncDomainsResource: + return AsyncDomainsResource(self._client) + + @cached_property + def custom_page_sets(self) -> AsyncCustomPageSetsResource: + return AsyncCustomPageSetsResource(self._client) + + @cached_property + def advanced_rules(self) -> AsyncAdvancedRulesResource: + return AsyncAdvancedRulesResource(self._client) + + @cached_property + def tags(self) -> AsyncTagsResource: + return AsyncTagsResource(self._client) + + @cached_property + def organizations(self) -> AsyncOrganizationsResource: + return AsyncOrganizationsResource(self._client) + + @cached_property + def insights(self) -> AsyncInsightsResource: + return AsyncInsightsResource(self._client) + + @cached_property + def ip_info(self) -> AsyncIPInfoResource: + return AsyncIPInfoResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncWaapResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers + """ + return AsyncWaapResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncWaapResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response + """ + return AsyncWaapResourceWithStreamingResponse(self) + + async def get_account_overview( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WaapGetAccountOverviewResponse: + """Get information about WAAP service for the client""" + return await self._get( + "/waap/v1/clients/me", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WaapGetAccountOverviewResponse, + ) + + +class WaapResourceWithRawResponse: + def __init__(self, waap: WaapResource) -> None: + self._waap = waap + + self.get_account_overview = to_raw_response_wrapper( + waap.get_account_overview, + ) + + @cached_property + def statistics(self) -> StatisticsResourceWithRawResponse: + return StatisticsResourceWithRawResponse(self._waap.statistics) + + @cached_property + def domains(self) -> DomainsResourceWithRawResponse: + return DomainsResourceWithRawResponse(self._waap.domains) + + @cached_property + def custom_page_sets(self) -> CustomPageSetsResourceWithRawResponse: + return CustomPageSetsResourceWithRawResponse(self._waap.custom_page_sets) + + @cached_property + def advanced_rules(self) -> AdvancedRulesResourceWithRawResponse: + return AdvancedRulesResourceWithRawResponse(self._waap.advanced_rules) + + @cached_property + def tags(self) -> TagsResourceWithRawResponse: + return TagsResourceWithRawResponse(self._waap.tags) + + @cached_property + def organizations(self) -> OrganizationsResourceWithRawResponse: + return OrganizationsResourceWithRawResponse(self._waap.organizations) + + @cached_property + def insights(self) -> InsightsResourceWithRawResponse: + return InsightsResourceWithRawResponse(self._waap.insights) + + @cached_property + def ip_info(self) -> IPInfoResourceWithRawResponse: + return IPInfoResourceWithRawResponse(self._waap.ip_info) + + +class AsyncWaapResourceWithRawResponse: + def __init__(self, waap: AsyncWaapResource) -> None: + self._waap = waap + + self.get_account_overview = async_to_raw_response_wrapper( + waap.get_account_overview, + ) + + @cached_property + def statistics(self) -> AsyncStatisticsResourceWithRawResponse: + return AsyncStatisticsResourceWithRawResponse(self._waap.statistics) + + @cached_property + def domains(self) -> AsyncDomainsResourceWithRawResponse: + return AsyncDomainsResourceWithRawResponse(self._waap.domains) + + @cached_property + def custom_page_sets(self) -> AsyncCustomPageSetsResourceWithRawResponse: + return AsyncCustomPageSetsResourceWithRawResponse(self._waap.custom_page_sets) + + @cached_property + def advanced_rules(self) -> AsyncAdvancedRulesResourceWithRawResponse: + return AsyncAdvancedRulesResourceWithRawResponse(self._waap.advanced_rules) + + @cached_property + def tags(self) -> AsyncTagsResourceWithRawResponse: + return AsyncTagsResourceWithRawResponse(self._waap.tags) + + @cached_property + def organizations(self) -> AsyncOrganizationsResourceWithRawResponse: + return AsyncOrganizationsResourceWithRawResponse(self._waap.organizations) + + @cached_property + def insights(self) -> AsyncInsightsResourceWithRawResponse: + return AsyncInsightsResourceWithRawResponse(self._waap.insights) + + @cached_property + def ip_info(self) -> AsyncIPInfoResourceWithRawResponse: + return AsyncIPInfoResourceWithRawResponse(self._waap.ip_info) + + +class WaapResourceWithStreamingResponse: + def __init__(self, waap: WaapResource) -> None: + self._waap = waap + + self.get_account_overview = to_streamed_response_wrapper( + waap.get_account_overview, + ) + + @cached_property + def statistics(self) -> StatisticsResourceWithStreamingResponse: + return StatisticsResourceWithStreamingResponse(self._waap.statistics) + + @cached_property + def domains(self) -> DomainsResourceWithStreamingResponse: + return DomainsResourceWithStreamingResponse(self._waap.domains) + + @cached_property + def custom_page_sets(self) -> CustomPageSetsResourceWithStreamingResponse: + return CustomPageSetsResourceWithStreamingResponse(self._waap.custom_page_sets) + + @cached_property + def advanced_rules(self) -> AdvancedRulesResourceWithStreamingResponse: + return AdvancedRulesResourceWithStreamingResponse(self._waap.advanced_rules) + + @cached_property + def tags(self) -> TagsResourceWithStreamingResponse: + return TagsResourceWithStreamingResponse(self._waap.tags) + + @cached_property + def organizations(self) -> OrganizationsResourceWithStreamingResponse: + return OrganizationsResourceWithStreamingResponse(self._waap.organizations) + + @cached_property + def insights(self) -> InsightsResourceWithStreamingResponse: + return InsightsResourceWithStreamingResponse(self._waap.insights) + + @cached_property + def ip_info(self) -> IPInfoResourceWithStreamingResponse: + return IPInfoResourceWithStreamingResponse(self._waap.ip_info) + + +class AsyncWaapResourceWithStreamingResponse: + def __init__(self, waap: AsyncWaapResource) -> None: + self._waap = waap + + self.get_account_overview = async_to_streamed_response_wrapper( + waap.get_account_overview, + ) + + @cached_property + def statistics(self) -> AsyncStatisticsResourceWithStreamingResponse: + return AsyncStatisticsResourceWithStreamingResponse(self._waap.statistics) + + @cached_property + def domains(self) -> AsyncDomainsResourceWithStreamingResponse: + return AsyncDomainsResourceWithStreamingResponse(self._waap.domains) + + @cached_property + def custom_page_sets(self) -> AsyncCustomPageSetsResourceWithStreamingResponse: + return AsyncCustomPageSetsResourceWithStreamingResponse(self._waap.custom_page_sets) + + @cached_property + def advanced_rules(self) -> AsyncAdvancedRulesResourceWithStreamingResponse: + return AsyncAdvancedRulesResourceWithStreamingResponse(self._waap.advanced_rules) + + @cached_property + def tags(self) -> AsyncTagsResourceWithStreamingResponse: + return AsyncTagsResourceWithStreamingResponse(self._waap.tags) + + @cached_property + def organizations(self) -> AsyncOrganizationsResourceWithStreamingResponse: + return AsyncOrganizationsResourceWithStreamingResponse(self._waap.organizations) + + @cached_property + def insights(self) -> AsyncInsightsResourceWithStreamingResponse: + return AsyncInsightsResourceWithStreamingResponse(self._waap.insights) + + @cached_property + def ip_info(self) -> AsyncIPInfoResourceWithStreamingResponse: + return AsyncIPInfoResourceWithStreamingResponse(self._waap.ip_info) diff --git a/src/gcore/types/__init__.py b/src/gcore/types/__init__.py new file mode 100644 index 00000000..f8ee8b14 --- /dev/null +++ b/src/gcore/types/__init__.py @@ -0,0 +1,3 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations diff --git a/src/gcore/types/cdn/__init__.py b/src/gcore/types/cdn/__init__.py new file mode 100644 index 00000000..92895e33 --- /dev/null +++ b/src/gcore/types/cdn/__init__.py @@ -0,0 +1,85 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .ssl_detail import SslDetail as SslDetail +from .aws_regions import AwsRegions as AwsRegions +from .cdn_account import CDNAccount as CDNAccount +from .cdn_metrics import CDNMetrics as CDNMetrics +from .cdn_resource import CDNResource as CDNResource +from .purge_status import PurgeStatus as PurgeStatus +from .cdn_log_entry import CDNLogEntry as CDNLogEntry +from .origin_groups import OriginGroups as OriginGroups +from .rule_template import RuleTemplate as RuleTemplate +from .ca_certificate import CaCertificate as CaCertificate +from .public_ip_list import PublicIPList as PublicIPList +from .alibaba_regions import AlibabaRegions as AlibabaRegions +from .log_list_params import LogListParams as LogListParams +from .ssl_detail_list import SslDetailList as SslDetailList +from .network_capacity import NetworkCapacity as NetworkCapacity +from .cdn_resource_list import CDNResourceList as CDNResourceList +from .cdn_account_limits import CDNAccountLimits as CDNAccountLimits +from .cdn_metrics_groups import CDNMetricsGroups as CDNMetricsGroups +from .cdn_metrics_values import CDNMetricsValues as CDNMetricsValues +from .metric_list_params import MetricListParams as MetricListParams +from .origin_groups_list import OriginGroupsList as OriginGroupsList +from .rule_template_list import RuleTemplateList as RuleTemplateList +from .ssl_request_status import SslRequestStatus as SslRequestStatus +from .usage_series_stats import UsageSeriesStats as UsageSeriesStats +from .ca_certificate_list import CaCertificateList as CaCertificateList +from .cdn_audit_log_entry import CDNAuditLogEntry as CDNAuditLogEntry +from .log_download_params import LogDownloadParams as LogDownloadParams +from .public_network_list import PublicNetworkList as PublicNetworkList +from .ip_range_list_params import IPRangeListParams as IPRangeListParams +from .resource_usage_stats import ResourceUsageStats as ResourceUsageStats +from .shield_list_response import ShieldListResponse as ShieldListResponse +from .audit_log_list_params import AuditLogListParams as AuditLogListParams +from .logs_aggregated_stats import LogsAggregatedStats as LogsAggregatedStats +from .cdn_available_features import CDNAvailableFeatures as CDNAvailableFeatures +from .certificate_list_params import CertificateListParams as CertificateListParams +from .shield_aggregated_stats import ShieldAggregatedStats as ShieldAggregatedStats +from .cdn_resource_list_params import CDNResourceListParams as CDNResourceListParams +from .ip_range_list_ips_params import IPRangeListIPsParams as IPRangeListIPsParams +from .logs_uploader_validation import LogsUploaderValidation as LogsUploaderValidation +from .origin_group_list_params import OriginGroupListParams as OriginGroupListParams +from .cdn_resource_purge_params import CDNResourcePurgeParams as CDNResourcePurgeParams +from .cdn_update_account_params import CDNUpdateAccountParams as CDNUpdateAccountParams +from .certificate_create_params import CertificateCreateParams as CertificateCreateParams +from .resource_aggregated_stats import ResourceAggregatedStats as ResourceAggregatedStats +from .cdn_resource_create_params import CDNResourceCreateParams as CDNResourceCreateParams +from .cdn_resource_update_params import CDNResourceUpdateParams as CDNResourceUpdateParams +from .certificate_replace_params import CertificateReplaceParams as CertificateReplaceParams +from .origin_group_create_params import OriginGroupCreateParams as OriginGroupCreateParams +from .origin_group_update_params import OriginGroupUpdateParams as OriginGroupUpdateParams +from .cdn_resource_replace_params import CDNResourceReplaceParams as CDNResourceReplaceParams +from .origin_group_replace_params import OriginGroupReplaceParams as OriginGroupReplaceParams +from .rule_template_create_params import RuleTemplateCreateParams as RuleTemplateCreateParams +from .rule_template_update_params import RuleTemplateUpdateParams as RuleTemplateUpdateParams +from .cdn_resource_prefetch_params import CDNResourcePrefetchParams as CDNResourcePrefetchParams +from .rule_template_replace_params import RuleTemplateReplaceParams as RuleTemplateReplaceParams +from .certificate_get_status_params import CertificateGetStatusParams as CertificateGetStatusParams +from .cdn_list_purge_statuses_params import CDNListPurgeStatusesParams as CDNListPurgeStatusesParams +from .cdn_list_purge_statuses_response import CDNListPurgeStatusesResponse as CDNListPurgeStatusesResponse +from .trusted_ca_certificate_list_params import TrustedCaCertificateListParams as TrustedCaCertificateListParams +from .trusted_ca_certificate_create_params import TrustedCaCertificateCreateParams as TrustedCaCertificateCreateParams +from .trusted_ca_certificate_replace_params import ( + TrustedCaCertificateReplaceParams as TrustedCaCertificateReplaceParams, +) +from .statistic_get_logs_usage_series_params import ( + StatisticGetLogsUsageSeriesParams as StatisticGetLogsUsageSeriesParams, +) +from .statistic_get_shield_usage_series_params import ( + StatisticGetShieldUsageSeriesParams as StatisticGetShieldUsageSeriesParams, +) +from .statistic_get_logs_usage_aggregated_params import ( + StatisticGetLogsUsageAggregatedParams as StatisticGetLogsUsageAggregatedParams, +) +from .statistic_get_resource_usage_series_params import ( + StatisticGetResourceUsageSeriesParams as StatisticGetResourceUsageSeriesParams, +) +from .statistic_get_shield_usage_aggregated_params import ( + StatisticGetShieldUsageAggregatedParams as StatisticGetShieldUsageAggregatedParams, +) +from .statistic_get_resource_usage_aggregated_params import ( + StatisticGetResourceUsageAggregatedParams as StatisticGetResourceUsageAggregatedParams, +) diff --git a/src/gcore/types/cdn/alibaba_regions.py b/src/gcore/types/cdn/alibaba_regions.py new file mode 100644 index 00000000..8be22234 --- /dev/null +++ b/src/gcore/types/cdn/alibaba_regions.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["AlibabaRegions", "AlibabaRegionItem"] + + +class AlibabaRegionItem(BaseModel): + id: Optional[int] = None + """Region ID.""" + + code: Optional[str] = None + """Region code.""" + + name: Optional[str] = None + """Region name.""" + + +AlibabaRegions: TypeAlias = List[AlibabaRegionItem] diff --git a/src/gcore/types/cdn/audit_log_list_params.py b/src/gcore/types/cdn/audit_log_list_params.py new file mode 100644 index 00000000..e70beede --- /dev/null +++ b/src/gcore/types/cdn/audit_log_list_params.py @@ -0,0 +1,73 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["AuditLogListParams"] + + +class AuditLogListParams(TypedDict, total=False): + client_id: int + """Client ID.""" + + limit: int + """Maximum number of items in response.""" + + max_requested_at: str + """End of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + You can specify a date with a time separated by a space, or just a date. + + Examples: + + - &`max_requested_at`=2021-05-05 12:00:00 + - &`max_requested_at`=2021-05-05 + """ + + method: str + """HTTP method type of requests. + + Use upper case only. + + Example: + + - ?method=DELETE + """ + + min_requested_at: str + """Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + You can specify a date with a time separated by a space, or just a date. + + Examples: + + - &`min_requested_at`=2021-05-05 12:00:00 + - &`min_requested_at`=2021-05-05 + """ + + offset: int + """Offset relative to the beginning of activity logs.""" + + path: str + """Exact URL path.""" + + remote_ip_address: str + """Exact IP address from which requests are sent.""" + + status_code: int + """Status code returned in the response. + + Specify the first numbers of a status code to get requests for a group of status + codes. + + To filter the activity logs by 4xx codes, use: + + - &`status_code`=4 - + """ + + token_id: int + """Permanent API token ID. Requests made with this token should be displayed.""" + + user_id: int + """User ID.""" diff --git a/src/gcore/types/cdn/aws_regions.py b/src/gcore/types/cdn/aws_regions.py new file mode 100644 index 00000000..0dccf9b9 --- /dev/null +++ b/src/gcore/types/cdn/aws_regions.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["AwsRegions", "AwsRegionItem"] + + +class AwsRegionItem(BaseModel): + id: Optional[int] = None + """Region ID.""" + + code: Optional[str] = None + """Region code.""" + + name: Optional[str] = None + """Region name.""" + + +AwsRegions: TypeAlias = List[AwsRegionItem] diff --git a/src/gcore/types/cdn/ca_certificate.py b/src/gcore/types/cdn/ca_certificate.py new file mode 100644 index 00000000..bc2cba57 --- /dev/null +++ b/src/gcore/types/cdn/ca_certificate.py @@ -0,0 +1,53 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["CaCertificate"] + + +class CaCertificate(BaseModel): + id: Optional[int] = None + """CA certificate ID.""" + + cert_issuer: Optional[str] = None + """Name of the certification center that issued the CA certificate.""" + + cert_subject_alt: Optional[str] = None + """Alternative domain names that the CA certificate secures.""" + + cert_subject_cn: Optional[str] = None + """Domain name that the CA certificate secures.""" + + deleted: Optional[bool] = None + """Defines whether the certificate has been deleted. Parameter is **deprecated**. + + Possible values: + + - **true** - Certificate has been deleted. + - **false** - Certificate has not been deleted. + """ + + has_related_resources: Optional[bool] = FieldInfo(alias="hasRelatedResources", default=None) + """Defines whether the CA certificate is used by a CDN resource. + + Possible values: + + - **true** - Certificate is used by a CDN resource. + - **false** - Certificate is not used by a CDN resource. + """ + + name: Optional[str] = None + """CA certificate name.""" + + ssl_certificate_chain: Optional[str] = FieldInfo(alias="sslCertificateChain", default=None) + """Parameter is **deprecated**.""" + + validity_not_after: Optional[str] = None + """Date when the CA certificate become untrusted (ISO 8601/RFC 3339 format, UTC.)""" + + validity_not_before: Optional[str] = None + """Date when the CA certificate become valid (ISO 8601/RFC 3339 format, UTC.)""" diff --git a/src/gcore/types/cdn/ca_certificate_list.py b/src/gcore/types/cdn/ca_certificate_list.py new file mode 100644 index 00000000..1f56b642 --- /dev/null +++ b/src/gcore/types/cdn/ca_certificate_list.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .ca_certificate import CaCertificate + +__all__ = ["CaCertificateList"] + +CaCertificateList: TypeAlias = List[CaCertificate] diff --git a/src/gcore/types/cdn/cdn_account.py b/src/gcore/types/cdn/cdn_account.py new file mode 100644 index 00000000..c9bccffb --- /dev/null +++ b/src/gcore/types/cdn/cdn_account.py @@ -0,0 +1,88 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["CDNAccount", "Service"] + + +class Service(BaseModel): + """Information about the CDN service status.""" + + enabled: Optional[bool] = None + """Defines whether the CDN service is activated. + + Possible values: + + - **true** - Service is activated. + - **false** - Service is not activated. + """ + + status: Optional[str] = None + """CDN service status. + + Possible values: + + - **new** - CDN service is not activated. + - **trial** - Free trial is in progress. + - **trialend** - Free trial has ended and CDN service is stopped. All CDN + resources are suspended. + - **activating** - CDN service is being activated. It can take up to 15 minutes. + - **active** - CDN service is active. + - **paused** - CDN service is stopped. All CDN resources are suspended. + - **deleted** - CDN service is stopped. All CDN resources are deleted. + """ + + updated: Optional[str] = None + """Date of the last CDN service status update (ISO 8601/RFC 3339 format, UTC.)""" + + +class CDNAccount(BaseModel): + id: Optional[int] = None + """Account ID.""" + + auto_suspend_enabled: Optional[bool] = None + """Defines whether resources will be deactivated automatically by inactivity. + + Possible values: + + - **true** - Resources will be deactivated. + - **false** - Resources will not be deactivated. + """ + + cdn_resources_rules_max_count: Optional[int] = None + """Limit on the number of rules for each CDN resource.""" + + cname: Optional[str] = None + """Domain zone to which a CNAME record of your CDN resources should be pointed.""" + + created: Optional[str] = None + """ + Date of the first synchronization with the Platform (ISO 8601/RFC 3339 format, + UTC.) + """ + + service: Optional[Service] = None + """Information about the CDN service status.""" + + updated: Optional[str] = None + """ + Date of the last update of information about CDN service (ISO 8601/RFC 3339 + format, UTC.) + """ + + use_balancer: Optional[bool] = None + """Defines whether custom balancing is used for content delivery. + + Possible values: + + - **true** - Custom balancing is used for content delivery. + - **false** - Custom balancing is not used for content delivery. + """ + + utilization_level: Optional[int] = None + """CDN traffic usage limit in gigabytes. + + When the limit is reached, we will send an email notification. + """ diff --git a/src/gcore/types/cdn/cdn_account_limits.py b/src/gcore/types/cdn/cdn_account_limits.py new file mode 100644 index 00000000..cb398ffa --- /dev/null +++ b/src/gcore/types/cdn/cdn_account_limits.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["CDNAccountLimits"] + + +class CDNAccountLimits(BaseModel): + id: Optional[int] = None + """Account ID.""" + + origins_in_group_limit: Optional[int] = None + """ + Maximum number of origins that can be added to the origin group on your tariff + plan. + """ + + resources_limit: Optional[int] = None + """Maximum number of CDN resources that can be created on your tariff plan.""" + + rules_limit: Optional[int] = None + """ + Maximum number of rules that can be created per CDN resource on your tariff + plan. + """ diff --git a/src/gcore/types/cdn/cdn_audit_log_entry.py b/src/gcore/types/cdn/cdn_audit_log_entry.py new file mode 100644 index 00000000..ec56b787 --- /dev/null +++ b/src/gcore/types/cdn/cdn_audit_log_entry.py @@ -0,0 +1,66 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["CDNAuditLogEntry", "Action"] + + +class Action(BaseModel): + action_type: Optional[str] = None + """Type of change. + + Possible values: + + - **D** - Object is deleted. + - **C** - Object is created. + - **U** - Object is updated. + """ + + state_after_request: Optional[object] = None + """JSON representation of object after the request.""" + + state_before_request: Optional[object] = None + """JSON representation of object before the request.""" + + +class CDNAuditLogEntry(BaseModel): + id: Optional[int] = None + """Activity logs record ID.""" + + actions: Optional[List[Action]] = None + """State of a requested object before and after the request.""" + + client_id: Optional[int] = None + """ID of the client who made the request.""" + + data: Optional[object] = None + """Request body.""" + + host: Optional[str] = None + """Host from which the request was made.""" + + method: Optional[str] = None + """Request HTTP method.""" + + path: Optional[str] = None + """Request URL.""" + + query_params: Optional[str] = None + """Request parameters.""" + + remote_ip_address: Optional[str] = None + """IP address from which the request was made.""" + + requested_at: Optional[str] = None + """Date and time when the request was made.""" + + status_code: Optional[int] = None + """Status code that is returned in the response.""" + + token_id: Optional[int] = None + """Permanent API token ID with which the request was made.""" + + user_id: Optional[int] = None + """ID of the user who made the request.""" diff --git a/src/gcore/types/cdn/cdn_available_features.py b/src/gcore/types/cdn/cdn_available_features.py new file mode 100644 index 00000000..ffeaf299 --- /dev/null +++ b/src/gcore/types/cdn/cdn_available_features.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["CDNAvailableFeatures", "FreeFeature", "PaidFeature"] + + +class FreeFeature(BaseModel): + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8601/RFC 3339 format, UTC.)""" + + feature_id: Optional[int] = None + """Feature ID.""" + + free_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + name: Optional[str] = None + """Feature name.""" + + +class PaidFeature(BaseModel): + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8601/RFC 3339 format, UTC.)""" + + feature_id: Optional[int] = None + """Feature ID.""" + + name: Optional[str] = None + """Feature name.""" + + paid_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + +class CDNAvailableFeatures(BaseModel): + id: Optional[int] = None + """Account ID.""" + + free_features: Optional[List[FreeFeature]] = None + """Free features available for your account.""" + + paid_features: Optional[List[PaidFeature]] = None + """Paid features available for your account.""" diff --git a/src/gcore/types/cdn/cdn_list_purge_statuses_params.py b/src/gcore/types/cdn/cdn_list_purge_statuses_params.py new file mode 100644 index 00000000..a0c3227b --- /dev/null +++ b/src/gcore/types/cdn/cdn_list_purge_statuses_params.py @@ -0,0 +1,67 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["CDNListPurgeStatusesParams"] + + +class CDNListPurgeStatusesParams(TypedDict, total=False): + cname: str + """Purges associated with a specific resource CNAME. + + Example: + + - &cname=example.com + """ + + from_created: str + """ + Start date and time of the requested time period (ISO 8601/RFC 3339 format, + UTC.) + + Examples: + + - &`from_created`=2021-06-14T00:00:00Z + - &`from_created`=2021-06-14T00:00:00.000Z + """ + + limit: int + """Maximum number of purges in the response.""" + + offset: int + """ + Number of purge requests in the response to skip starting from the beginning of + the requested period. + """ + + purge_type: str + """Purge requests with a certain purge type. + + Possible values: + + - **`purge_by_pattern`** - Purge by Pattern. + - **`purge_by_url`** - Purge by URL. + - **`purge_all`** - Purge All. + """ + + status: str + """Purge with a certain status. + + Possible values: + + - **In progress** + - **Successful** + - **Failed** + - **Status report disabled** + """ + + to_created: str + """End date and time of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + Examples: + + - &`to_created`=2021-06-15T00:00:00Z + - &`to_created`=2021-06-15T00:00:00.000Z + """ diff --git a/src/gcore/types/cdn/cdn_list_purge_statuses_response.py b/src/gcore/types/cdn/cdn_list_purge_statuses_response.py new file mode 100644 index 00000000..e0a38e7c --- /dev/null +++ b/src/gcore/types/cdn/cdn_list_purge_statuses_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .purge_status import PurgeStatus + +__all__ = ["CDNListPurgeStatusesResponse"] + +CDNListPurgeStatusesResponse: TypeAlias = List[PurgeStatus] diff --git a/src/gcore/types/cdn/cdn_log_entry.py b/src/gcore/types/cdn/cdn_log_entry.py new file mode 100644 index 00000000..b9d193f9 --- /dev/null +++ b/src/gcore/types/cdn/cdn_log_entry.py @@ -0,0 +1,72 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["CDNLogEntry", "Data", "Meta"] + + +class Data(BaseModel): + cache_status: Optional[str] = None + """Cache status: HIT, MISS, etc.""" + + client_ip: Optional[str] = None + """IP address from that the request was received.""" + + cname: Optional[str] = None + """CDN resource custom domain.""" + + datacenter: Optional[str] = None + """Data center where the request was processed.""" + + method: Optional[str] = None + """HTTP method used in the request.""" + + path: Optional[str] = None + """Path requested.""" + + referer: Optional[str] = None + """Value of 'Referer' header.""" + + resource_id: Optional[int] = None + """CDN resource ID.""" + + sent_http_content_type: Optional[str] = None + """ + Value of the Content-Type HTTP header, indicating the MIME type of the resource + being transmitted. + """ + + size: Optional[int] = None + """Response size in bytes.""" + + status: Optional[int] = None + """HTTP status code.""" + + tcpinfo_rtt: Optional[int] = None + """ + Time required to transmit a complete TCP segment: from the first bit to the + last. + """ + + timestamp: Optional[int] = None + """Log timestamp.""" + + user_agent: Optional[str] = None + """Value of 'User-Agent' header.""" + + +class Meta(BaseModel): + """Contains meta-information.""" + + count: Optional[int] = None + """Total number of records which match given parameters.""" + + +class CDNLogEntry(BaseModel): + data: Optional[List[Data]] = None + """Contains requested logs.""" + + meta: Optional[Meta] = None + """Contains meta-information.""" diff --git a/src/gcore/types/cdn/cdn_metrics.py b/src/gcore/types/cdn/cdn_metrics.py new file mode 100644 index 00000000..26537ff3 --- /dev/null +++ b/src/gcore/types/cdn/cdn_metrics.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import TypeAlias + +from ..._models import BaseModel +from .cdn_metrics_groups import CDNMetricsGroups +from .cdn_metrics_values import CDNMetricsValues + +__all__ = ["CDNMetrics", "Data"] + +Data: TypeAlias = Union[CDNMetricsValues, CDNMetricsGroups] + + +class CDNMetrics(BaseModel): + data: Optional[Data] = None + """ + If no grouping was requested then "data" holds an array of metric values. If at + least one field is specified in "group_by" then "data" is an object whose + properties are groups, which may include other groups; the last group will hold + array of metrics values. + """ diff --git a/src/gcore/types/cdn/cdn_metrics_groups.py b/src/gcore/types/cdn/cdn_metrics_groups.py new file mode 100644 index 00000000..a88712d6 --- /dev/null +++ b/src/gcore/types/cdn/cdn_metrics_groups.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .cdn_metrics_values import CDNMetricsValues + +__all__ = ["CDNMetricsGroups"] + + +class CDNMetricsGroups(BaseModel): + group: Optional[CDNMetricsValues] = None + """List of requested metrics sorted by timestamp in ascending order.""" diff --git a/src/gcore/types/cdn/cdn_metrics_values.py b/src/gcore/types/cdn/cdn_metrics_values.py new file mode 100644 index 00000000..cd63a18c --- /dev/null +++ b/src/gcore/types/cdn/cdn_metrics_values.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["CDNMetricsValues", "CDNMetricsValueItem"] + + +class CDNMetricsValueItem(BaseModel): + metric: Optional[float] = None + """Metrics value.""" + + timestamp: Optional[int] = None + """Start timestamp of interval.""" + + +CDNMetricsValues: TypeAlias = List[CDNMetricsValueItem] diff --git a/src/gcore/types/cdn/cdn_resource.py b/src/gcore/types/cdn/cdn_resource.py new file mode 100644 index 00000000..7e143119 --- /dev/null +++ b/src/gcore/types/cdn/cdn_resource.py @@ -0,0 +1,2288 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = [ + "CDNResource", + "Options", + "OptionsAllowedHTTPMethods", + "OptionsBotProtection", + "OptionsBotProtectionBotChallenge", + "OptionsBrotliCompression", + "OptionsBrowserCacheSettings", + "OptionsCacheHTTPHeaders", + "OptionsCors", + "OptionsCountryACL", + "OptionsDisableCache", + "OptionsDisableProxyForceRanges", + "OptionsEdgeCacheSettings", + "OptionsFastedge", + "OptionsFastedgeOnRequestBody", + "OptionsFastedgeOnRequestHeaders", + "OptionsFastedgeOnResponseBody", + "OptionsFastedgeOnResponseHeaders", + "OptionsFetchCompressed", + "OptionsFollowOriginRedirect", + "OptionsForceReturn", + "OptionsForceReturnTimeInterval", + "OptionsForwardHostHeader", + "OptionsGzipOn", + "OptionsHostHeader", + "OptionsHttp3Enabled", + "OptionsIgnoreCookie", + "OptionsIgnoreQueryString", + "OptionsImageStack", + "OptionsIPAddressACL", + "OptionsLimitBandwidth", + "OptionsProxyCacheKey", + "OptionsProxyCacheMethodsSet", + "OptionsProxyConnectTimeout", + "OptionsProxyReadTimeout", + "OptionsQueryParamsBlacklist", + "OptionsQueryParamsWhitelist", + "OptionsQueryStringForwarding", + "OptionsRedirectHTTPToHTTPS", + "OptionsRedirectHTTPSToHTTP", + "OptionsReferrerACL", + "OptionsRequestLimiter", + "OptionsResponseHeadersHidingPolicy", + "OptionsRewrite", + "OptionsSecureKey", + "OptionsSlice", + "OptionsSni", + "OptionsStale", + "OptionsStaticResponseHeaders", + "OptionsStaticResponseHeadersValue", + "OptionsStaticHeaders", + "OptionsStaticRequestHeaders", + "OptionsTlsVersions", + "OptionsUseDefaultLeChain", + "OptionsUseDns01LeChallenge", + "OptionsUseRsaLeCert", + "OptionsUserAgentACL", + "OptionsWaap", + "OptionsWebsockets", +] + + +class OptionsAllowedHTTPMethods(BaseModel): + """HTTP methods allowed for content requests from the CDN.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[Literal["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]] + + +class OptionsBotProtectionBotChallenge(BaseModel): + """Controls the bot challenge module state.""" + + enabled: Optional[bool] = None + """Possible values: + + - **true** - Bot challenge is enabled. + - **false** - Bot challenge is disabled. + """ + + +class OptionsBotProtection(BaseModel): + """ + Allows to prevent online services from overloading and ensure your business workflow running smoothly. + """ + + bot_challenge: OptionsBotProtectionBotChallenge + """Controls the bot challenge module state.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsBrotliCompression(BaseModel): + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN resource and want to enable `brotli_compression` in a rule, you must specify `fetch_compressed:false` in the rule. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[ + Literal[ + "application/javascript", + "application/json", + "application/vnd.ms-fontobject", + "application/wasm", + "application/x-font-ttf", + "application/x-javascript", + "application/xml", + "application/xml+rss", + "image/svg+xml", + "image/x-icon", + "text/css", + "text/html", + "text/javascript", + "text/plain", + "text/xml", + ] + ] + """Allows to select the content types you want to compress. + + `text/html` is a mandatory content type. + """ + + +class OptionsBrowserCacheSettings(BaseModel): + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Set the cache expiration time to '0s' to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsCacheHTTPHeaders(BaseModel): + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[str] + + +class OptionsCors(BaseModel): + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header to a response to a browser. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[str] + """Value of the Access-Control-Allow-Origin header. + + Possible values: + + - **Adds \\** as the Access-Control-Allow-Origin header value** - Content will be + uploaded for requests from any domain. `"value": ["*"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value if the + origin matches one of the listed domains** - Content will be uploaded only for + requests from the domains specified in the field. + `"value": ["domain.com", "second.dom.com"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value** - + Content will be uploaded for requests from any domain, and the domain from + which the request was sent will be added to the "Access-Control-Allow-Origin" + header in the response. `"value": ["$http_origin"]` + """ + + always: Optional[bool] = None + """ + Defines whether the Access-Control-Allow-Origin header should be added to a + response from CDN regardless of response code. + + Possible values: + + - **true** - Header will be added to a response regardless of response code. + - **false** - Header will only be added to responses with codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsCountryACL(BaseModel): + """Enables control access to content for specified countries.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: List[str] + """List of countries according to ISO-3166-1. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of countries for which access is prohibited. + - **deny** - List of countries for which access is allowed. + """ + + policy_type: Literal["allow", "deny"] + """Defines the type of CDN resource access policy. + + Possible values: + + - **allow** - Access is allowed for all the countries except for those specified + in `excepted_values` field. + - **deny** - Access is denied for all the countries except for those specified + in `excepted_values` field. + """ + + +class OptionsDisableCache(BaseModel): + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - content caching is disabled. + - **false** - content caching is enabled. + """ + + +class OptionsDisableProxyForceRanges(BaseModel): + """Allows 206 responses regardless of the settings of an origin source.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsEdgeCacheSettings(BaseModel): + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + custom_values: Optional[Dict[str, str]] = None + """ + A MAP object representing the caching time in seconds for a response with a + specific response code. + + These settings have a higher priority than the `value` field. + + - Use `any` key to specify caching time for all response codes. + - Use `0s` value to disable caching for a specific response code. + """ + + default: Optional[str] = None + """Enables content caching according to the origin cache settings. + + The value is applied to the following response codes 200, 201, 204, 206, 301, + 302, 303, 304, 307, 308, if an origin server does not have caching HTTP headers. + + Responses with other codes will not be cached. + + The maximum duration is any equivalent to `1y`. + """ + + value: Optional[str] = None + """Caching time. + + The value is applied to the following response codes: 200, 206, 301, 302. + Responses with codes 4xx, 5xx will not be cached. + + Use `0s` to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsFastedgeOnRequestBody(BaseModel): + """ + Allows to configure FastEdge application that will be called to handle request body as soon as CDN receives incoming HTTP request. + """ + + app_id: str + """The ID of the application in FastEdge.""" + + enabled: Optional[bool] = None + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: Optional[bool] = None + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: Optional[bool] = None + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: Optional[bool] = None + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnRequestHeaders(BaseModel): + """ + Allows to configure FastEdge application that will be called to handle request headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + app_id: str + """The ID of the application in FastEdge.""" + + enabled: Optional[bool] = None + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: Optional[bool] = None + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: Optional[bool] = None + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: Optional[bool] = None + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseBody(BaseModel): + """ + Allows to configure FastEdge application that will be called to handle response body before CDN sends the HTTP response. + """ + + app_id: str + """The ID of the application in FastEdge.""" + + enabled: Optional[bool] = None + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: Optional[bool] = None + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: Optional[bool] = None + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: Optional[bool] = None + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseHeaders(BaseModel): + """ + Allows to configure FastEdge application that will be called to handle response headers before CDN sends the HTTP response. + """ + + app_id: str + """The ID of the application in FastEdge.""" + + enabled: Optional[bool] = None + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: Optional[bool] = None + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: Optional[bool] = None + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: Optional[bool] = None + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedge(BaseModel): + """ + Allows to configure FastEdge app to be called on different request/response phases. + + Note: At least one of `on_request_headers`, `on_request_body`, `on_response_headers`, or `on_response_body` must be specified. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + on_request_body: Optional[OptionsFastedgeOnRequestBody] = None + """ + Allows to configure FastEdge application that will be called to handle request + body as soon as CDN receives incoming HTTP request. + """ + + on_request_headers: Optional[OptionsFastedgeOnRequestHeaders] = None + """ + Allows to configure FastEdge application that will be called to handle request + headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + on_response_body: Optional[OptionsFastedgeOnResponseBody] = None + """ + Allows to configure FastEdge application that will be called to handle response + body before CDN sends the HTTP response. + """ + + on_response_headers: Optional[OptionsFastedgeOnResponseHeaders] = None + """ + Allows to configure FastEdge application that will be called to handle response + headers before CDN sends the HTTP response. + """ + + +class OptionsFetchCompressed(BaseModel): + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If you enable it in CDN resource and want to use `gzipON` and `brotli_compression` in a rule, you have to specify `"fetch_compressed": false` in the rule. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsFollowOriginRedirect(BaseModel): + """ + Enables redirection from origin. + If the origin server returns a redirect, the option allows the CDN to pull the requested content from the origin server that was returned in the redirect. + """ + + codes: List[Literal[301, 302, 303, 307, 308]] + """Redirect status code that the origin server returns. + + To serve up to date content to end users, you will need to purge the cache after + managing the option. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsForceReturnTimeInterval(BaseModel): + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + end_time: str + """Time until which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + start_time: str + """Time from which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + time_zone: Optional[str] = None + """Time zone used to calculate time.""" + + +class OptionsForceReturn(BaseModel): + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + body: str + """URL for redirection or text.""" + + code: int + """Status code value.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + time_interval: Optional[OptionsForceReturnTimeInterval] = None + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + +class OptionsForwardHostHeader(BaseModel): + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsGzipOn(BaseModel): + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in rules. If you enable `fetch_compressed` in CDN resource and want to enable `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsHostHeader(BaseModel): + """ + Sets the Host header that CDN servers use when request content from an origin server. + Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Host Header value.""" + + +class OptionsHttp3Enabled(BaseModel): + """Enables HTTP/3 protocol for content delivery. + + `http3_enabled` option works only with `"sslEnabled": true`. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsIgnoreCookie(BaseModel): + """ + Defines whether the files with the Set-Cookies header are cached as one file or as different ones. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled, files with cookies are cached as one file. + - **false** - Option is disabled, files with cookies are cached as different + files. + """ + + +class OptionsIgnoreQueryString(BaseModel): + """ + How a file with different query strings is cached: either as one object (option is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsImageStack(BaseModel): + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically converts them to WebP or AVIF format. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + avif_enabled: Optional[bool] = None + """Enables or disables automatic conversion of JPEG and PNG images to AVI format.""" + + png_lossless: Optional[bool] = None + """Enables or disables compression without quality loss for PNG format.""" + + quality: Optional[int] = None + """Defines quality settings for JPG and PNG images. + + The higher the value, the better the image quality, and the larger the file size + after conversion. + """ + + webp_enabled: Optional[bool] = None + """Enables or disables automatic conversion of JPEG and PNG images to WebP format.""" + + +class OptionsIPAddressACL(BaseModel): + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: List[str] + """List of IP addresses with a subnet mask. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of IP addresses for which access is prohibited. + - **deny** - List of IP addresses for which access is allowed. + + Examples: + + - `192.168.3.2/32` + - `2a03:d000:2980:7::8/128` + """ + + policy_type: Literal["allow", "deny"] + """IP access policy type. + + Possible values: + + - **allow** - Allow access to all IPs except IPs specified in "excepted_values" + field. + - **deny** - Deny access to all IPs except IPs specified in "excepted_values" + field. + """ + + +class OptionsLimitBandwidth(BaseModel): + """Allows to control the download speed per connection.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + limit_type: Literal["static", "dynamic"] + """Method of controlling the download speed per connection. + + Possible values: + + - **static** - Use speed and buffer fields to set the download speed limit. + - **dynamic** - Use query strings **speed** and **buffer** to set the download + speed limit. + + For example, when requesting content at the link + + ``` + http://cdn.example.com/video.mp4?speed=50k&buffer=500k + ``` + + the download speed will be limited to 50kB/s after 500 kB. + """ + + buffer: Optional[int] = None + """Amount of downloaded data after which the user will be rate limited.""" + + speed: Optional[int] = None + """Maximum download speed per connection.""" + + +class OptionsProxyCacheKey(BaseModel): + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will not work. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Key for caching.""" + + +class OptionsProxyCacheMethodsSet(BaseModel): + """Caching for POST requests along with default GET and HEAD.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsProxyConnectTimeout(BaseModel): + """The time limit for establishing a connection with the origin.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Timeout value in seconds. + + Supported range: **1s - 5s**. + """ + + +class OptionsProxyReadTimeout(BaseModel): + """ + The time limit for receiving a partial response from the origin. + If no response is received within this time, the connection will be closed. + + **Note:** + When used with a WebSocket connection, this option supports values only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Timeout value in seconds. + + Supported range: **1s - 30s**. + """ + + +class OptionsQueryParamsBlacklist(BaseModel): + """ + Files with the specified query parameters are cached as one object, files with other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[str] + """List of query parameters.""" + + +class OptionsQueryParamsWhitelist(BaseModel): + """ + Files with the specified query parameters are cached as different objects, files with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[str] + """List of query parameters.""" + + +class OptionsQueryStringForwarding(BaseModel): + """ + The Query String Forwarding feature allows for the seamless transfer of parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication tokens or tracking information, are consistently passed along from the playlist manifest to the individual media segments. + This is particularly useful for maintaining continuity in security, analytics, and any other parameter-based operations across the entire media delivery workflow. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + forward_from_file_types: List[str] + """ + The `forward_from_files_types` field specifies the types of playlist files from + which parameters will be extracted and forwarded. This typically includes + formats that list multiple media chunk references, such as HLS and DASH + playlists. Parameters associated with these playlist files (like query strings + or headers) will be propagated to the chunks they reference. + """ + + forward_to_file_types: List[str] + """ + The field specifies the types of media chunk files to which parameters, + extracted from playlist files, will be forwarded. These refer to the actual + segments of media content that are delivered to viewers. Ensuring the correct + parameters are forwarded to these files is crucial for maintaining the integrity + of the streaming session. + """ + + forward_except_keys: Optional[List[str]] = None + """ + The `forward_except_keys` field provides a mechanism to exclude specific + parameters from being forwarded from playlist files to media chunk files. By + listing certain keys in this field, you can ensure that these parameters are + omitted during the forwarding process. This is particularly useful for + preventing sensitive or irrelevant information from being included in requests + for media chunks, thereby enhancing security and optimizing performance. + """ + + forward_only_keys: Optional[List[str]] = None + """ + The `forward_only_keys` field allows for granular control over which specific + parameters are forwarded from playlist files to media chunk files. By specifying + certain keys, only those parameters will be propagated, ensuring that only + relevant information is passed along. This is particularly useful for security + and performance optimization, as it prevents unnecessary or sensitive data from + being included in requests for media chunks. + """ + + +class OptionsRedirectHTTPToHTTPS(BaseModel): + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsRedirectHTTPSToHTTP(BaseModel): + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsReferrerACL(BaseModel): + """Controls access to the CDN resource content for specified domain names.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: List[str] + """ + List of domain names or wildcard domains (without protocol: `http://` or + `https://`.) + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of domain names for which access is prohibited. + - **deny** - List of IP domain names for which access is allowed. + + Examples: + + - `example.com` + - `*.example.com` + """ + + policy_type: Literal["allow", "deny"] + """Policy type. + + Possible values: + + - **allow** - Allow access to all domain names except the domain names specified + in `excepted_values` field. + - **deny** - Deny access to all domain names except the domain names specified + in `excepted_values` field. + """ + + +class OptionsRequestLimiter(BaseModel): + """Option allows to limit the amount of HTTP requests.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + rate: int + """Maximum request rate.""" + + burst: Optional[int] = None + + delay: Optional[int] = None + + rate_unit: Optional[Literal["r/s", "r/m"]] = None + """Units of measurement for the `rate` field. + + Possible values: + + - **r/s** - Requests per second. + - **r/m** - Requests per minute. + + If the rate is less than one request per second, it is specified in request per + minute (r/m.) + """ + + +class OptionsResponseHeadersHidingPolicy(BaseModel): + """Hides HTTP headers from an origin server in the CDN response.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted: List[str] + """List of HTTP headers. + + Parameter meaning depends on the value of the `mode` field: + + - **show** - List of HTTP headers to hide from response. + - **hide** - List of HTTP headers to include in response. Other HTTP headers + will be hidden. + + The following headers are required and cannot be hidden from response: + + - `Connection` + - `Content-Length` + - `Content-Type` + - `Date` + - `Server` + """ + + mode: Literal["hide", "show"] + """How HTTP headers are hidden from the response. + + Possible values: + + - **show** - Hide only HTTP headers listed in the `excepted` field. + - **hide** - Hide all HTTP headers except headers listed in the "excepted" + field. + """ + + +class OptionsRewrite(BaseModel): + """Changes and redirects requests from the CDN to the origin. + + It operates according to the [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) configuration. + """ + + body: str + """Path for the Rewrite option. + + Example: + + - `/(.*) /media/$1` + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + flag: Optional[Literal["break", "last", "redirect", "permanent"]] = None + """Flag for the Rewrite option. + + Possible values: + + - **last** - Stop processing the current set of `ngx_http_rewrite_module` + directives and start a search for a new location matching changed URI. + - **break** - Stop processing the current set of the Rewrite option. + - **redirect** - Return a temporary redirect with the 302 code; used when a + replacement string does not start with `http://`, `https://`, or `$scheme`. + - **permanent** - Return a permanent redirect with the 301 code. + """ + + +class OptionsSecureKey(BaseModel): + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + key: Optional[str] = None + """Key generated on your side that will be used for URL signing.""" + + type: Optional[Literal[0, 2]] = None + """Type of URL signing. + + Possible types: + + - **Type 0** - Includes end user IP to secure token generation. + - **Type 2** - Excludes end user IP from secure token generation. + """ + + +class OptionsSlice(BaseModel): + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per part.) This reduces time to first byte. + + The option is based on the [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` options enabled. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsSni(BaseModel): + """ + The hostname that is added to SNI requests from CDN servers to the origin server via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not have a dedicated IP address. + If the origin server presents multiple certificates, SNI allows the origin server to know which certificate to use for the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + custom_hostname: str + """Custom SNI hostname. + + It is required if `sni_type` is set to custom. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + sni_type: Optional[Literal["dynamic", "custom"]] = None + """SNI (Server Name Indication) type. + + Possible values: + + - **dynamic** - SNI hostname depends on `hostHeader` and `forward_host_header` + options. It has several possible combinations: + - If the `hostHeader` option is enabled and specified, SNI hostname matches the + Host header. + - If the `forward_host_header` option is enabled and has true value, SNI + hostname matches the Host header used in the request made to a CDN. + - If the `hostHeader` and `forward_host_header` options are disabled, SNI + hostname matches the primary CNAME. + - **custom** - custom SNI hostname is in use. + """ + + +class OptionsStale(BaseModel): + """Serves stale cached content in case of origin unavailability.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[ + Literal[ + "error", + "http_403", + "http_404", + "http_429", + "http_500", + "http_502", + "http_503", + "http_504", + "invalid_header", + "timeout", + "updating", + ] + ] + """Defines list of errors for which "Always online" option is applied.""" + + +class OptionsStaticResponseHeadersValue(BaseModel): + name: str + """HTTP Header name. + + Restrictions: + + - Maximum 128 symbols. + - Latin letters (A-Z, a-z,) numbers (0-9,) dashes, and underscores only. + """ + + value: List[str] + """Header value. + + Restrictions: + + - Maximum 512 symbols. + - Letters (a-z), numbers (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ + /|\";:?.,><{}[]). + - Must start with a letter, number, asterisk or {. + - Multiple values can be added. + """ + + always: Optional[bool] = None + """ + Defines whether the header will be added to a response from CDN regardless of + response code. + + Possible values: + + - **true** - Header will be added to a response from CDN regardless of response + code. + - **false** - Header will be added only to the following response codes: 200, + 201, 204, 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsStaticResponseHeaders(BaseModel): + """Custom HTTP Headers that a CDN server adds to a response.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[OptionsStaticResponseHeadersValue] + + +class OptionsStaticHeaders(BaseModel): + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP Headers can be specified. May contain a header with multiple values. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: object + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 128 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsStaticRequestHeaders(BaseModel): + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Dict[str, str] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 255 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsTlsVersions(BaseModel): + """ + List of SSL/TLS protocol versions allowed for HTTPS connections from end users to the domain. + + When the option is disabled, all protocols versions are allowed. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[Literal["SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"]] + """List of SSL/TLS protocol versions (case sensitive).""" + + +class OptionsUseDefaultLeChain(BaseModel): + """Let's Encrypt certificate chain. + + The specified chain will be used during the next Let's Encrypt certificate issue or renewal. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Default Let's Encrypt certificate chain. This is a deprecated + version, use it only for compatibilities with Android devices 7.1.1 or lower. + - **false** - Alternative Let's Encrypt certificate chain. + """ + + +class OptionsUseDns01LeChallenge(BaseModel): + """DNS-01 challenge to issue a Let's Encrypt certificate for the resource. + + DNS service should be activated to enable this option. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - DNS-01 challenge is used to issue Let's Encrypt certificate. + - **false** - HTTP-01 challenge is used to issue Let's Encrypt certificate. + """ + + +class OptionsUseRsaLeCert(BaseModel): + """RSA Let's Encrypt certificate type for the CDN resource. + + The specified value will be used during the next Let's Encrypt certificate issue or renewal. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - RSA Let's Encrypt certificate. + - **false** - ECDSA Let's Encrypt certificate. + """ + + +class OptionsUserAgentACL(BaseModel): + """Controls access to the content for specified User-Agents.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: List[str] + """List of User-Agents that will be allowed/denied. + + The meaning of the parameter depends on `policy_type`: + + - **allow** - List of User-Agents for which access is prohibited. + - **deny** - List of User-Agents for which access is allowed. + + You can provide exact User-Agent strings or regular expressions. Regular + expressions must start with `~` (case-sensitive) or `~*` (case-insensitive). + + Use an empty string `""` to allow/deny access when the User-Agent header is + empty. + """ + + policy_type: Literal["allow", "deny"] + """User-Agents policy type. + + Possible values: + + - **allow** - Allow access for all User-Agents except specified in + `excepted_values` field. + - **deny** - Deny access for all User-Agents except specified in + `excepted_values` field. + """ + + +class OptionsWaap(BaseModel): + """Allows to enable WAAP (Web Application and API Protection).""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsWebsockets(BaseModel): + """Enables or disables WebSockets connections to an origin server.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class Options(BaseModel): + """List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. + Option may inherit its value from the global account settings. + """ + + allowed_http_methods: Optional[OptionsAllowedHTTPMethods] = FieldInfo(alias="allowedHttpMethods", default=None) + """HTTP methods allowed for content requests from the CDN.""" + + bot_protection: Optional[OptionsBotProtection] = None + """ + Allows to prevent online services from overloading and ensure your business + workflow running smoothly. + """ + + brotli_compression: Optional[OptionsBrotliCompression] = None + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is + activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, + even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` + options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides + `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN + resource and want to enable `brotli_compression` in a rule, you must specify + `fetch_compressed:false` in the rule. + """ + + browser_cache_settings: Optional[OptionsBrowserCacheSettings] = None + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + cache_http_headers: Optional[OptionsCacheHTTPHeaders] = None + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + cors: Optional[OptionsCors] = None + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header + to a response to a browser. + """ + + country_acl: Optional[OptionsCountryACL] = None + """Enables control access to content for specified countries.""" + + disable_cache: Optional[OptionsDisableCache] = None + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + disable_proxy_force_ranges: Optional[OptionsDisableProxyForceRanges] = None + """Allows 206 responses regardless of the settings of an origin source.""" + + edge_cache_settings: Optional[OptionsEdgeCacheSettings] = None + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + fastedge: Optional[OptionsFastedge] = None + """ + Allows to configure FastEdge app to be called on different request/response + phases. + + Note: At least one of `on_request_headers`, `on_request_body`, + `on_response_headers`, or `on_response_body` must be specified. + """ + + fetch_compressed: Optional[OptionsFetchCompressed] = None + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress + your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or + `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If + you enable it in CDN resource and want to use `gzipON` and + `brotli_compression` in a rule, you have to specify + `"fetch_compressed": false` in the rule. + """ + + follow_origin_redirect: Optional[OptionsFollowOriginRedirect] = None + """ + Enables redirection from origin. If the origin server returns a redirect, the + option allows the CDN to pull the requested content from the origin server that + was returned in the redirect. + """ + + force_return: Optional[OptionsForceReturn] = None + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this + option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + forward_host_header: Optional[OptionsForwardHostHeader] = None + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + gzip_on: Optional[OptionsGzipOn] = FieldInfo(alias="gzipOn", default=None) + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` + options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in + rules. If you enable `fetch_compressed` in CDN resource and want to enable + `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + host_header: Optional[OptionsHostHeader] = FieldInfo(alias="hostHeader", default=None) + """ + Sets the Host header that CDN servers use when request content from an origin + server. Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + http3_enabled: Optional[OptionsHttp3Enabled] = None + """Enables HTTP/3 protocol for content delivery. + + `http3_enabled` option works only with `"sslEnabled": true`. + """ + + ignore_cookie: Optional[OptionsIgnoreCookie] = None + """ + Defines whether the files with the Set-Cookies header are cached as one file or + as different ones. + """ + + ignore_query_string: Optional[OptionsIgnoreQueryString] = FieldInfo(alias="ignoreQueryString", default=None) + """ + How a file with different query strings is cached: either as one object (option + is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + image_stack: Optional[OptionsImageStack] = None + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically + converts them to WebP or AVIF format. + """ + + ip_address_acl: Optional[OptionsIPAddressACL] = None + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, + you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. + [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + limit_bandwidth: Optional[OptionsLimitBandwidth] = None + """Allows to control the download speed per connection.""" + + proxy_cache_key: Optional[OptionsProxyCacheKey] = None + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache + and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will + not work. + """ + + proxy_cache_methods_set: Optional[OptionsProxyCacheMethodsSet] = None + """Caching for POST requests along with default GET and HEAD.""" + + proxy_connect_timeout: Optional[OptionsProxyConnectTimeout] = None + """The time limit for establishing a connection with the origin.""" + + proxy_read_timeout: Optional[OptionsProxyReadTimeout] = None + """ + The time limit for receiving a partial response from the origin. If no response + is received within this time, the connection will be closed. + + **Note:** When used with a WebSocket connection, this option supports values + only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + query_params_blacklist: Optional[OptionsQueryParamsBlacklist] = None + """ + Files with the specified query parameters are cached as one object, files with + other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_params_whitelist: Optional[OptionsQueryParamsWhitelist] = None + """ + Files with the specified query parameters are cached as different objects, files + with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_string_forwarding: Optional[OptionsQueryStringForwarding] = None + """ + The Query String Forwarding feature allows for the seamless transfer of + parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication + tokens or tracking information, are consistently passed along from the playlist + manifest to the individual media segments. This is particularly useful for + maintaining continuity in security, analytics, and any other parameter-based + operations across the entire media delivery workflow. + """ + + redirect_http_to_https: Optional[OptionsRedirectHTTPToHTTPS] = None + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + redirect_https_to_http: Optional[OptionsRedirectHTTPSToHTTP] = None + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + referrer_acl: Optional[OptionsReferrerACL] = None + """Controls access to the CDN resource content for specified domain names.""" + + request_limiter: Optional[OptionsRequestLimiter] = None + """Option allows to limit the amount of HTTP requests.""" + + response_headers_hiding_policy: Optional[OptionsResponseHeadersHidingPolicy] = None + """Hides HTTP headers from an origin server in the CDN response.""" + + rewrite: Optional[OptionsRewrite] = None + """Changes and redirects requests from the CDN to the origin. + + It operates according to the + [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) + configuration. + """ + + secure_key: Optional[OptionsSecureKey] = None + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + slice: Optional[OptionsSlice] = None + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per + part.) This reduces time to first byte. + + The option is based on the + [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` + options enabled. + """ + + sni: Optional[OptionsSni] = None + """ + The hostname that is added to SNI requests from CDN servers to the origin server + via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not + have a dedicated IP address. If the origin server presents multiple + certificates, SNI allows the origin server to know which certificate to use for + the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + stale: Optional[OptionsStale] = None + """Serves stale cached content in case of origin unavailability.""" + + static_response_headers: Optional[OptionsStaticResponseHeaders] = None + """Custom HTTP Headers that a CDN server adds to a response.""" + + static_headers: Optional[OptionsStaticHeaders] = FieldInfo(alias="staticHeaders", default=None) + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP + Headers can be specified. May contain a header with multiple values. + """ + + static_request_headers: Optional[OptionsStaticRequestHeaders] = FieldInfo( + alias="staticRequestHeaders", default=None + ) + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + tls_versions: Optional[OptionsTlsVersions] = None + """ + List of SSL/TLS protocol versions allowed for HTTPS connections from end users + to the domain. + + When the option is disabled, all protocols versions are allowed. + """ + + use_default_le_chain: Optional[OptionsUseDefaultLeChain] = None + """Let's Encrypt certificate chain. + + The specified chain will be used during the next Let's Encrypt certificate issue + or renewal. + """ + + use_dns01_le_challenge: Optional[OptionsUseDns01LeChallenge] = None + """DNS-01 challenge to issue a Let's Encrypt certificate for the resource. + + DNS service should be activated to enable this option. + """ + + use_rsa_le_cert: Optional[OptionsUseRsaLeCert] = None + """RSA Let's Encrypt certificate type for the CDN resource. + + The specified value will be used during the next Let's Encrypt certificate issue + or renewal. + """ + + user_agent_acl: Optional[OptionsUserAgentACL] = None + """Controls access to the content for specified User-Agents.""" + + waap: Optional[OptionsWaap] = None + """Allows to enable WAAP (Web Application and API Protection).""" + + websockets: Optional[OptionsWebsockets] = None + """Enables or disables WebSockets connections to an origin server.""" + + +class CDNResource(BaseModel): + id: Optional[int] = None + """CDN resource ID.""" + + active: Optional[bool] = None + """Enables or disables a CDN resource. + + Possible values: + + - **true** - CDN resource is active. Content is being delivered. + - **false** - CDN resource is deactivated. Content is not being delivered. + """ + + can_purge_by_urls: Optional[bool] = None + """Defines whether the CDN resource can be used for purge by URLs feature. + + It's available only in case the CDN resource has enabled `ignore_vary_header` + option. + """ + + client: Optional[int] = None + """ID of an account to which the CDN resource belongs.""" + + cname: Optional[str] = None + """Delivery domains that will be used for content delivery through a CDN. + + Delivery domains should be added to your DNS settings. + """ + + created: Optional[str] = None + """Date of CDN resource creation.""" + + deleted: Optional[bool] = None + """Defines whether CDN resource has been deleted. + + Possible values: + + - **true** - CDN resource is deleted. + - **false** - CDN resource is not deleted. + """ + + description: Optional[str] = None + """Optional comment describing the CDN resource.""" + + enabled: Optional[bool] = None + """Enables or disables a CDN resource change by a user. + + Possible values: + + - **true** - CDN resource is enabled and can be changed. Content can be + delivered. + - **false** - CDN resource is disabled and cannot be changed. Content can not be + delivered. + """ + + full_custom_enabled: Optional[bool] = None + """Defines whether the CDN resource has a custom configuration. + + Possible values: + + - **true** - CDN resource has a custom configuration. You cannot change resource + settings, except for the SSL certificate. To change other settings, contact + technical support. + - **false** - CDN resource has a regular configuration. You can change CDN + resource settings. + """ + + is_primary: Optional[bool] = None + """Defines whether a CDN resource has a cache zone shared with other CDN resources. + + Possible values: + + - **true** - CDN resource is main and has a shared caching zone with other CDN + resources, which are called reserve. + - **false** - CDN resource is reserve and it has a shared caching zone with the + main CDN resource. You cannot change some options, create rules, set up origin + shielding and use the reserve resource for Streaming. + - **null** - CDN resource does not have a shared cache zone. + + The main CDN resource is specified in the `primary_resource` field. It cannot be + suspended unless all related reserve CDN resources are suspended. + """ + + name: Optional[str] = None + """CDN resource name.""" + + options: Optional[Options] = None + """List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. Option may + inherit its value from the global account settings. + """ + + origin_group: Optional[int] = FieldInfo(alias="originGroup", default=None) + """Origin group ID with which the CDN resource is associated.""" + + origin_group_name: Optional[str] = FieldInfo(alias="originGroup_name", default=None) + """Origin group name.""" + + origin_protocol: Optional[Literal["HTTP", "HTTPS", "MATCH"]] = FieldInfo(alias="originProtocol", default=None) + """Protocol used by CDN servers to request content from an origin source. + + Possible values: + + - **HTTPS** - CDN servers will connect to the origin via HTTPS. + - **HTTP** - CDN servers will connect to the origin via HTTP. + - **MATCH** - connection protocol will be chosen automatically (content on the + origin source should be available for the CDN both through HTTP and HTTPS). + + If protocol is not specified, HTTP is used to connect to an origin server. + """ + + preset_applied: Optional[bool] = None + """Defines whether the CDN resource has a preset applied. + + Possible values: + + - **true** - CDN resource has a preset applied. CDN resource options included in + the preset cannot be edited. + - **false** - CDN resource does not have a preset applied. + """ + + primary_resource: Optional[int] = None + """ + ID of the main CDN resource which has a shared caching zone with a reserve CDN + resource. + + If the parameter is not empty, then the current CDN resource is the reserve. You + cannot change some options, create rules, set up origin shielding, or use the + reserve CDN resource for Streaming. + """ + + proxy_ssl_ca: Optional[int] = None + """ID of the trusted CA certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + """ + + proxy_ssl_data: Optional[int] = None + """ID of the SSL certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + """ + + proxy_ssl_enabled: Optional[bool] = None + """ + Enables or disables SSL certificate validation of the origin server before + completing any connection. + + Possible values: + + - **true** - Origin SSL certificate validation is enabled. + - **false** - Origin SSL certificate validation is disabled. + """ + + rules: Optional[List[object]] = None + """Rules configured for the CDN resource.""" + + secondary_hostnames: Optional[List[str]] = FieldInfo(alias="secondaryHostnames", default=None) + """ + Additional delivery domains (CNAMEs) that will be used to deliver content via + the CDN. + + Up to ten additional CNAMEs are possible. + """ + + shield_dc: Optional[str] = None + """Name of the origin shielding location data center. + + Parameter returns **null** if origin shielding is disabled. + """ + + shield_enabled: Optional[bool] = None + """Defines whether origin shield is active and working for the CDN resource. + + Possible values: + + - **true** - Origin shield is active. + - **false** - Origin shield is not active. + """ + + shield_routing_map: Optional[int] = None + """ + Defines whether the origin shield with a dynamic location is enabled for the CDN + resource. + + To manage origin shielding, you must contact customer support. + """ + + shielded: Optional[bool] = None + """Defines whether origin shielding feature is enabled for the resource. + + Possible values: + + - **true** - Origin shielding is enabled. + - **false** - Origin shielding is disabled. + """ + + ssl_data: Optional[int] = FieldInfo(alias="sslData", default=None) + """ID of the SSL certificate linked to the CDN resource. + + Can be used only with `"sslEnabled": true`. + """ + + ssl_enabled: Optional[bool] = FieldInfo(alias="sslEnabled", default=None) + """Defines whether the HTTPS protocol enabled for content delivery. + + Possible values: + + - **true** - HTTPS is enabled. + - **false** - HTTPS is disabled. + """ + + status: Optional[Literal["active", "suspended", "processed", "deleted"]] = None + """CDN resource status. + + Possible values: + + - **active** - CDN resource is active. Content is available to users. + - **suspended** - CDN resource is suspended. Content is not available to users. + - **processed** - CDN resource has recently been created and is currently being + processed. It will take about fifteen minutes to propagate it to all + locations. + - **deleted** - CDN resource is deleted. + """ + + suspend_date: Optional[str] = None + """ + Date when the CDN resource was suspended automatically if there is no traffic on + it for 90 days. + + Not specified if the resource was not stopped due to lack of traffic. + """ + + suspended: Optional[bool] = None + """ + Defines whether the CDN resource has been automatically suspended because there + was no traffic on it for 90 days. + + Possible values: + + - **true** - CDN resource is currently automatically suspended. + - **false** - CDN resource is not automatically suspended. + + You can enable CDN resource using the `active` field. If there is no traffic on + the CDN resource within seven days following activation, it will be suspended + again. + + To avoid CDN resource suspension due to no traffic, contact technical support. + """ + + updated: Optional[str] = None + """Date of the last CDN resource update.""" + + vp_enabled: Optional[bool] = None + """Defines whether the CDN resource is integrated with the Streaming Platform. + + Possible values: + + - **true** - CDN resource is configured for Streaming Platform. Changing + resource settings can affect its operation. + - **false** - CDN resource is not configured for Streaming Platform. + """ + + waap_domain_id: Optional[str] = None + """The ID of the associated WAAP domain.""" diff --git a/src/gcore/types/cdn/cdn_resource_create_params.py b/src/gcore/types/cdn/cdn_resource_create_params.py new file mode 100644 index 00000000..58df5896 --- /dev/null +++ b/src/gcore/types/cdn/cdn_resource_create_params.py @@ -0,0 +1,2141 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable, Optional +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = [ + "CDNResourceCreateParams", + "Options", + "OptionsAllowedHTTPMethods", + "OptionsBotProtection", + "OptionsBotProtectionBotChallenge", + "OptionsBrotliCompression", + "OptionsBrowserCacheSettings", + "OptionsCacheHTTPHeaders", + "OptionsCors", + "OptionsCountryACL", + "OptionsDisableCache", + "OptionsDisableProxyForceRanges", + "OptionsEdgeCacheSettings", + "OptionsFastedge", + "OptionsFastedgeOnRequestBody", + "OptionsFastedgeOnRequestHeaders", + "OptionsFastedgeOnResponseBody", + "OptionsFastedgeOnResponseHeaders", + "OptionsFetchCompressed", + "OptionsFollowOriginRedirect", + "OptionsForceReturn", + "OptionsForceReturnTimeInterval", + "OptionsForwardHostHeader", + "OptionsGzipOn", + "OptionsHostHeader", + "OptionsHttp3Enabled", + "OptionsIgnoreCookie", + "OptionsIgnoreQueryString", + "OptionsImageStack", + "OptionsIPAddressACL", + "OptionsLimitBandwidth", + "OptionsProxyCacheKey", + "OptionsProxyCacheMethodsSet", + "OptionsProxyConnectTimeout", + "OptionsProxyReadTimeout", + "OptionsQueryParamsBlacklist", + "OptionsQueryParamsWhitelist", + "OptionsQueryStringForwarding", + "OptionsRedirectHTTPToHTTPS", + "OptionsRedirectHTTPSToHTTP", + "OptionsReferrerACL", + "OptionsRequestLimiter", + "OptionsResponseHeadersHidingPolicy", + "OptionsRewrite", + "OptionsSecureKey", + "OptionsSlice", + "OptionsSni", + "OptionsStale", + "OptionsStaticResponseHeaders", + "OptionsStaticResponseHeadersValue", + "OptionsStaticHeaders", + "OptionsStaticRequestHeaders", + "OptionsTlsVersions", + "OptionsUseDefaultLeChain", + "OptionsUseDns01LeChallenge", + "OptionsUseRsaLeCert", + "OptionsUserAgentACL", + "OptionsWaap", + "OptionsWebsockets", +] + + +class CDNResourceCreateParams(TypedDict, total=False): + cname: Required[str] + """Delivery domains that will be used for content delivery through a CDN. + + Delivery domains should be added to your DNS settings. + """ + + active: bool + """Enables or disables a CDN resource. + + Possible values: + + - **true** - CDN resource is active. Content is being delivered. + - **false** - CDN resource is deactivated. Content is not being delivered. + """ + + description: str + """Optional comment describing the CDN resource.""" + + name: Optional[str] + """CDN resource name.""" + + options: Options + """List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. Option may + inherit its value from the global account settings. + """ + + origin: str + """IP address or domain name of the origin and the port, if custom port is used. + + Exactly one of `origin` or `originGroup` must be provided during resource + creation. + """ + + origin_group: Annotated[int, PropertyInfo(alias="originGroup")] + """Origin group ID with which the CDN resource is associated. + + Exactly one of `origin` or `originGroup` must be provided during resource + creation. + """ + + origin_protocol: Annotated[Literal["HTTP", "HTTPS", "MATCH"], PropertyInfo(alias="originProtocol")] + """Protocol used by CDN servers to request content from an origin source. + + Possible values: + + - **HTTPS** - CDN servers will connect to the origin via HTTPS. + - **HTTP** - CDN servers will connect to the origin via HTTP. + - **MATCH** - connection protocol will be chosen automatically (content on the + origin source should be available for the CDN both through HTTP and HTTPS). + + If protocol is not specified, HTTP is used to connect to an origin server. + """ + + primary_resource: Optional[int] + """ + ID of the main CDN resource which has a shared caching zone with a reserve CDN + resource. + + If the parameter is not empty, then the current CDN resource is the reserve. You + cannot change some options, create rules, set up origin shielding, or use the + reserve CDN resource for Streaming. + """ + + proxy_ssl_ca: Optional[int] + """ID of the trusted CA certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + """ + + proxy_ssl_data: Optional[int] + """ID of the SSL certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + """ + + proxy_ssl_enabled: bool + """ + Enables or disables SSL certificate validation of the origin server before + completing any connection. + + Possible values: + + - **true** - Origin SSL certificate validation is enabled. + - **false** - Origin SSL certificate validation is disabled. + """ + + secondary_hostnames: Annotated[SequenceNotStr[str], PropertyInfo(alias="secondaryHostnames")] + """ + Additional delivery domains (CNAMEs) that will be used to deliver content via + the CDN. + + Up to ten additional CNAMEs are possible. + """ + + ssl_data: Annotated[Optional[int], PropertyInfo(alias="sslData")] + """ID of the SSL certificate linked to the CDN resource. + + Can be used only with `"sslEnabled": true`. + """ + + ssl_enabled: Annotated[bool, PropertyInfo(alias="sslEnabled")] + """Defines whether the HTTPS protocol enabled for content delivery. + + Possible values: + + - **true** - HTTPS is enabled. + - **false** - HTTPS is disabled. + """ + + waap_api_domain_enabled: bool + """Defines whether the associated WAAP Domain is identified as an API Domain. + + Possible values: + + - **true** - The associated WAAP Domain is designated as an API Domain. + - **false** - The associated WAAP Domain is not designated as an API Domain. + """ + + +class OptionsAllowedHTTPMethods(TypedDict, total=False): + """HTTP methods allowed for content requests from the CDN.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[List[Literal["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]]] + + +class OptionsBotProtectionBotChallenge(TypedDict, total=False): + """Controls the bot challenge module state.""" + + enabled: bool + """Possible values: + + - **true** - Bot challenge is enabled. + - **false** - Bot challenge is disabled. + """ + + +class OptionsBotProtection(TypedDict, total=False): + """ + Allows to prevent online services from overloading and ensure your business workflow running smoothly. + """ + + bot_challenge: Required[OptionsBotProtectionBotChallenge] + """Controls the bot challenge module state.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsBrotliCompression(TypedDict, total=False): + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN resource and want to enable `brotli_compression` in a rule, you must specify `fetch_compressed:false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "application/javascript", + "application/json", + "application/vnd.ms-fontobject", + "application/wasm", + "application/x-font-ttf", + "application/x-javascript", + "application/xml", + "application/xml+rss", + "image/svg+xml", + "image/x-icon", + "text/css", + "text/html", + "text/javascript", + "text/plain", + "text/xml", + ] + ] + ] + """Allows to select the content types you want to compress. + + `text/html` is a mandatory content type. + """ + + +class OptionsBrowserCacheSettings(TypedDict, total=False): + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Set the cache expiration time to '0s' to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsCacheHTTPHeaders(TypedDict, total=False): + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + + +class OptionsCors(TypedDict, total=False): + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header to a response to a browser. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """Value of the Access-Control-Allow-Origin header. + + Possible values: + + - **Adds \\** as the Access-Control-Allow-Origin header value** - Content will be + uploaded for requests from any domain. `"value": ["*"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value if the + origin matches one of the listed domains** - Content will be uploaded only for + requests from the domains specified in the field. + `"value": ["domain.com", "second.dom.com"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value** - + Content will be uploaded for requests from any domain, and the domain from + which the request was sent will be added to the "Access-Control-Allow-Origin" + header in the response. `"value": ["$http_origin"]` + """ + + always: bool + """ + Defines whether the Access-Control-Allow-Origin header should be added to a + response from CDN regardless of response code. + + Possible values: + + - **true** - Header will be added to a response regardless of response code. + - **false** - Header will only be added to responses with codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsCountryACL(TypedDict, total=False): + """Enables control access to content for specified countries.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of countries according to ISO-3166-1. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of countries for which access is prohibited. + - **deny** - List of countries for which access is allowed. + """ + + policy_type: Required[Literal["allow", "deny"]] + """Defines the type of CDN resource access policy. + + Possible values: + + - **allow** - Access is allowed for all the countries except for those specified + in `excepted_values` field. + - **deny** - Access is denied for all the countries except for those specified + in `excepted_values` field. + """ + + +class OptionsDisableCache(TypedDict, total=False): + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - content caching is disabled. + - **false** - content caching is enabled. + """ + + +class OptionsDisableProxyForceRanges(TypedDict, total=False): + """Allows 206 responses regardless of the settings of an origin source.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsEdgeCacheSettings(TypedDict, total=False): + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + custom_values: Dict[str, str] + """ + A MAP object representing the caching time in seconds for a response with a + specific response code. + + These settings have a higher priority than the `value` field. + + - Use `any` key to specify caching time for all response codes. + - Use `0s` value to disable caching for a specific response code. + """ + + default: str + """Enables content caching according to the origin cache settings. + + The value is applied to the following response codes 200, 201, 204, 206, 301, + 302, 303, 304, 307, 308, if an origin server does not have caching HTTP headers. + + Responses with other codes will not be cached. + + The maximum duration is any equivalent to `1y`. + """ + + value: str + """Caching time. + + The value is applied to the following response codes: 200, 206, 301, 302. + Responses with codes 4xx, 5xx will not be cached. + + Use `0s` to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsFastedgeOnRequestBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request body as soon as CDN receives incoming HTTP request. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnRequestHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response body before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response headers before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedge(TypedDict, total=False): + """ + Allows to configure FastEdge app to be called on different request/response phases. + + Note: At least one of `on_request_headers`, `on_request_body`, `on_response_headers`, or `on_response_body` must be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + on_request_body: OptionsFastedgeOnRequestBody + """ + Allows to configure FastEdge application that will be called to handle request + body as soon as CDN receives incoming HTTP request. + """ + + on_request_headers: OptionsFastedgeOnRequestHeaders + """ + Allows to configure FastEdge application that will be called to handle request + headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + on_response_body: OptionsFastedgeOnResponseBody + """ + Allows to configure FastEdge application that will be called to handle response + body before CDN sends the HTTP response. + """ + + on_response_headers: OptionsFastedgeOnResponseHeaders + """ + Allows to configure FastEdge application that will be called to handle response + headers before CDN sends the HTTP response. + """ + + +class OptionsFetchCompressed(TypedDict, total=False): + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If you enable it in CDN resource and want to use `gzipON` and `brotli_compression` in a rule, you have to specify `"fetch_compressed": false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsFollowOriginRedirect(TypedDict, total=False): + """ + Enables redirection from origin. + If the origin server returns a redirect, the option allows the CDN to pull the requested content from the origin server that was returned in the redirect. + """ + + codes: Required[Iterable[Literal[301, 302, 303, 307, 308]]] + """Redirect status code that the origin server returns. + + To serve up to date content to end users, you will need to purge the cache after + managing the option. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsForceReturnTimeInterval(TypedDict, total=False): + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + end_time: Required[str] + """Time until which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + start_time: Required[str] + """Time from which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + time_zone: str + """Time zone used to calculate time.""" + + +class OptionsForceReturn(TypedDict, total=False): + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + body: Required[str] + """URL for redirection or text.""" + + code: Required[int] + """Status code value.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + time_interval: Optional[OptionsForceReturnTimeInterval] + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + +class OptionsForwardHostHeader(TypedDict, total=False): + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsGzipOn(TypedDict, total=False): + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in rules. If you enable `fetch_compressed` in CDN resource and want to enable `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsHostHeader(TypedDict, total=False): + """ + Sets the Host header that CDN servers use when request content from an origin server. + Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Host Header value.""" + + +class OptionsHttp3Enabled(TypedDict, total=False): + """Enables HTTP/3 protocol for content delivery. + + `http3_enabled` option works only with `"sslEnabled": true`. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsIgnoreCookie(TypedDict, total=False): + """ + Defines whether the files with the Set-Cookies header are cached as one file or as different ones. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled, files with cookies are cached as one file. + - **false** - Option is disabled, files with cookies are cached as different + files. + """ + + +class OptionsIgnoreQueryString(TypedDict, total=False): + """ + How a file with different query strings is cached: either as one object (option is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsImageStack(TypedDict, total=False): + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically converts them to WebP or AVIF format. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + avif_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to AVI format.""" + + png_lossless: bool + """Enables or disables compression without quality loss for PNG format.""" + + quality: int + """Defines quality settings for JPG and PNG images. + + The higher the value, the better the image quality, and the larger the file size + after conversion. + """ + + webp_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to WebP format.""" + + +class OptionsIPAddressACL(TypedDict, total=False): + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of IP addresses with a subnet mask. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of IP addresses for which access is prohibited. + - **deny** - List of IP addresses for which access is allowed. + + Examples: + + - `192.168.3.2/32` + - `2a03:d000:2980:7::8/128` + """ + + policy_type: Required[Literal["allow", "deny"]] + """IP access policy type. + + Possible values: + + - **allow** - Allow access to all IPs except IPs specified in "excepted_values" + field. + - **deny** - Deny access to all IPs except IPs specified in "excepted_values" + field. + """ + + +class OptionsLimitBandwidth(TypedDict, total=False): + """Allows to control the download speed per connection.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + limit_type: Required[Literal["static", "dynamic"]] + """Method of controlling the download speed per connection. + + Possible values: + + - **static** - Use speed and buffer fields to set the download speed limit. + - **dynamic** - Use query strings **speed** and **buffer** to set the download + speed limit. + + For example, when requesting content at the link + + ``` + http://cdn.example.com/video.mp4?speed=50k&buffer=500k + ``` + + the download speed will be limited to 50kB/s after 500 kB. + """ + + buffer: int + """Amount of downloaded data after which the user will be rate limited.""" + + speed: int + """Maximum download speed per connection.""" + + +class OptionsProxyCacheKey(TypedDict, total=False): + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will not work. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Key for caching.""" + + +class OptionsProxyCacheMethodsSet(TypedDict, total=False): + """Caching for POST requests along with default GET and HEAD.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsProxyConnectTimeout(TypedDict, total=False): + """The time limit for establishing a connection with the origin.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 5s**. + """ + + +class OptionsProxyReadTimeout(TypedDict, total=False): + """ + The time limit for receiving a partial response from the origin. + If no response is received within this time, the connection will be closed. + + **Note:** + When used with a WebSocket connection, this option supports values only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 30s**. + """ + + +class OptionsQueryParamsBlacklist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as one object, files with other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryParamsWhitelist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as different objects, files with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryStringForwarding(TypedDict, total=False): + """ + The Query String Forwarding feature allows for the seamless transfer of parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication tokens or tracking information, are consistently passed along from the playlist manifest to the individual media segments. + This is particularly useful for maintaining continuity in security, analytics, and any other parameter-based operations across the entire media delivery workflow. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + forward_from_file_types: Required[SequenceNotStr[str]] + """ + The `forward_from_files_types` field specifies the types of playlist files from + which parameters will be extracted and forwarded. This typically includes + formats that list multiple media chunk references, such as HLS and DASH + playlists. Parameters associated with these playlist files (like query strings + or headers) will be propagated to the chunks they reference. + """ + + forward_to_file_types: Required[SequenceNotStr[str]] + """ + The field specifies the types of media chunk files to which parameters, + extracted from playlist files, will be forwarded. These refer to the actual + segments of media content that are delivered to viewers. Ensuring the correct + parameters are forwarded to these files is crucial for maintaining the integrity + of the streaming session. + """ + + forward_except_keys: SequenceNotStr[str] + """ + The `forward_except_keys` field provides a mechanism to exclude specific + parameters from being forwarded from playlist files to media chunk files. By + listing certain keys in this field, you can ensure that these parameters are + omitted during the forwarding process. This is particularly useful for + preventing sensitive or irrelevant information from being included in requests + for media chunks, thereby enhancing security and optimizing performance. + """ + + forward_only_keys: SequenceNotStr[str] + """ + The `forward_only_keys` field allows for granular control over which specific + parameters are forwarded from playlist files to media chunk files. By specifying + certain keys, only those parameters will be propagated, ensuring that only + relevant information is passed along. This is particularly useful for security + and performance optimization, as it prevents unnecessary or sensitive data from + being included in requests for media chunks. + """ + + +class OptionsRedirectHTTPToHTTPS(TypedDict, total=False): + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsRedirectHTTPSToHTTP(TypedDict, total=False): + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsReferrerACL(TypedDict, total=False): + """Controls access to the CDN resource content for specified domain names.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """ + List of domain names or wildcard domains (without protocol: `http://` or + `https://`.) + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of domain names for which access is prohibited. + - **deny** - List of IP domain names for which access is allowed. + + Examples: + + - `example.com` + - `*.example.com` + """ + + policy_type: Required[Literal["allow", "deny"]] + """Policy type. + + Possible values: + + - **allow** - Allow access to all domain names except the domain names specified + in `excepted_values` field. + - **deny** - Deny access to all domain names except the domain names specified + in `excepted_values` field. + """ + + +class OptionsRequestLimiter(TypedDict, total=False): + """Option allows to limit the amount of HTTP requests.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + rate: Required[int] + """Maximum request rate.""" + + rate_unit: Literal["r/s", "r/m"] + """Units of measurement for the `rate` field. + + Possible values: + + - **r/s** - Requests per second. + - **r/m** - Requests per minute. + + If the rate is less than one request per second, it is specified in request per + minute (r/m.) + """ + + +class OptionsResponseHeadersHidingPolicy(TypedDict, total=False): + """Hides HTTP headers from an origin server in the CDN response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted: Required[SequenceNotStr[str]] + """List of HTTP headers. + + Parameter meaning depends on the value of the `mode` field: + + - **show** - List of HTTP headers to hide from response. + - **hide** - List of HTTP headers to include in response. Other HTTP headers + will be hidden. + + The following headers are required and cannot be hidden from response: + + - `Connection` + - `Content-Length` + - `Content-Type` + - `Date` + - `Server` + """ + + mode: Required[Literal["hide", "show"]] + """How HTTP headers are hidden from the response. + + Possible values: + + - **show** - Hide only HTTP headers listed in the `excepted` field. + - **hide** - Hide all HTTP headers except headers listed in the "excepted" + field. + """ + + +class OptionsRewrite(TypedDict, total=False): + """Changes and redirects requests from the CDN to the origin. + + It operates according to the [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) configuration. + """ + + body: Required[str] + """Path for the Rewrite option. + + Example: + + - `/(.*) /media/$1` + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + flag: Literal["break", "last", "redirect", "permanent"] + """Flag for the Rewrite option. + + Possible values: + + - **last** - Stop processing the current set of `ngx_http_rewrite_module` + directives and start a search for a new location matching changed URI. + - **break** - Stop processing the current set of the Rewrite option. + - **redirect** - Return a temporary redirect with the 302 code; used when a + replacement string does not start with `http://`, `https://`, or `$scheme`. + - **permanent** - Return a permanent redirect with the 301 code. + """ + + +class OptionsSecureKey(TypedDict, total=False): + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + key: Required[Optional[str]] + """Key generated on your side that will be used for URL signing.""" + + type: Literal[0, 2] + """Type of URL signing. + + Possible types: + + - **Type 0** - Includes end user IP to secure token generation. + - **Type 2** - Excludes end user IP from secure token generation. + """ + + +class OptionsSlice(TypedDict, total=False): + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per part.) This reduces time to first byte. + + The option is based on the [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` options enabled. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsSni(TypedDict, total=False): + """ + The hostname that is added to SNI requests from CDN servers to the origin server via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not have a dedicated IP address. + If the origin server presents multiple certificates, SNI allows the origin server to know which certificate to use for the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + custom_hostname: Required[str] + """Custom SNI hostname. + + It is required if `sni_type` is set to custom. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + sni_type: Literal["dynamic", "custom"] + """SNI (Server Name Indication) type. + + Possible values: + + - **dynamic** - SNI hostname depends on `hostHeader` and `forward_host_header` + options. It has several possible combinations: + - If the `hostHeader` option is enabled and specified, SNI hostname matches the + Host header. + - If the `forward_host_header` option is enabled and has true value, SNI + hostname matches the Host header used in the request made to a CDN. + - If the `hostHeader` and `forward_host_header` options are disabled, SNI + hostname matches the primary CNAME. + - **custom** - custom SNI hostname is in use. + """ + + +class OptionsStale(TypedDict, total=False): + """Serves stale cached content in case of origin unavailability.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "error", + "http_403", + "http_404", + "http_429", + "http_500", + "http_502", + "http_503", + "http_504", + "invalid_header", + "timeout", + "updating", + ] + ] + ] + """Defines list of errors for which "Always online" option is applied.""" + + +class OptionsStaticResponseHeadersValue(TypedDict, total=False): + name: Required[str] + """HTTP Header name. + + Restrictions: + + - Maximum 128 symbols. + - Latin letters (A-Z, a-z,) numbers (0-9,) dashes, and underscores only. + """ + + value: Required[SequenceNotStr[str]] + """Header value. + + Restrictions: + + - Maximum 512 symbols. + - Letters (a-z), numbers (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ + /|\";:?.,><{}[]). + - Must start with a letter, number, asterisk or {. + - Multiple values can be added. + """ + + always: bool + """ + Defines whether the header will be added to a response from CDN regardless of + response code. + + Possible values: + + - **true** - Header will be added to a response from CDN regardless of response + code. + - **false** - Header will be added only to the following response codes: 200, + 201, 204, 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsStaticResponseHeaders(TypedDict, total=False): + """Custom HTTP Headers that a CDN server adds to a response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Iterable[OptionsStaticResponseHeadersValue]] + + +class OptionsStaticHeaders(TypedDict, total=False): + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP Headers can be specified. May contain a header with multiple values. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[object] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 128 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsStaticRequestHeaders(TypedDict, total=False): + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Dict[str, str]] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 255 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsTlsVersions(TypedDict, total=False): + """ + List of SSL/TLS protocol versions allowed for HTTPS connections from end users to the domain. + + When the option is disabled, all protocols versions are allowed. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[List[Literal["SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"]]] + """List of SSL/TLS protocol versions (case sensitive).""" + + +class OptionsUseDefaultLeChain(TypedDict, total=False): + """Let's Encrypt certificate chain. + + The specified chain will be used during the next Let's Encrypt certificate issue or renewal. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Default Let's Encrypt certificate chain. This is a deprecated + version, use it only for compatibilities with Android devices 7.1.1 or lower. + - **false** - Alternative Let's Encrypt certificate chain. + """ + + +class OptionsUseDns01LeChallenge(TypedDict, total=False): + """DNS-01 challenge to issue a Let's Encrypt certificate for the resource. + + DNS service should be activated to enable this option. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - DNS-01 challenge is used to issue Let's Encrypt certificate. + - **false** - HTTP-01 challenge is used to issue Let's Encrypt certificate. + """ + + +class OptionsUseRsaLeCert(TypedDict, total=False): + """RSA Let's Encrypt certificate type for the CDN resource. + + The specified value will be used during the next Let's Encrypt certificate issue or renewal. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - RSA Let's Encrypt certificate. + - **false** - ECDSA Let's Encrypt certificate. + """ + + +class OptionsUserAgentACL(TypedDict, total=False): + """Controls access to the content for specified User-Agents.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of User-Agents that will be allowed/denied. + + The meaning of the parameter depends on `policy_type`: + + - **allow** - List of User-Agents for which access is prohibited. + - **deny** - List of User-Agents for which access is allowed. + + You can provide exact User-Agent strings or regular expressions. Regular + expressions must start with `~` (case-sensitive) or `~*` (case-insensitive). + + Use an empty string `""` to allow/deny access when the User-Agent header is + empty. + """ + + policy_type: Required[Literal["allow", "deny"]] + """User-Agents policy type. + + Possible values: + + - **allow** - Allow access for all User-Agents except specified in + `excepted_values` field. + - **deny** - Deny access for all User-Agents except specified in + `excepted_values` field. + """ + + +class OptionsWaap(TypedDict, total=False): + """Allows to enable WAAP (Web Application and API Protection).""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsWebsockets(TypedDict, total=False): + """Enables or disables WebSockets connections to an origin server.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class Options(TypedDict, total=False): + """List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. + Option may inherit its value from the global account settings. + """ + + allowed_http_methods: Annotated[Optional[OptionsAllowedHTTPMethods], PropertyInfo(alias="allowedHttpMethods")] + """HTTP methods allowed for content requests from the CDN.""" + + bot_protection: Optional[OptionsBotProtection] + """ + Allows to prevent online services from overloading and ensure your business + workflow running smoothly. + """ + + brotli_compression: Optional[OptionsBrotliCompression] + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is + activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, + even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` + options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides + `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN + resource and want to enable `brotli_compression` in a rule, you must specify + `fetch_compressed:false` in the rule. + """ + + browser_cache_settings: Optional[OptionsBrowserCacheSettings] + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + cache_http_headers: Optional[OptionsCacheHTTPHeaders] + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + cors: Optional[OptionsCors] + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header + to a response to a browser. + """ + + country_acl: Optional[OptionsCountryACL] + """Enables control access to content for specified countries.""" + + disable_cache: Optional[OptionsDisableCache] + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + disable_proxy_force_ranges: Optional[OptionsDisableProxyForceRanges] + """Allows 206 responses regardless of the settings of an origin source.""" + + edge_cache_settings: Optional[OptionsEdgeCacheSettings] + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + fastedge: Optional[OptionsFastedge] + """ + Allows to configure FastEdge app to be called on different request/response + phases. + + Note: At least one of `on_request_headers`, `on_request_body`, + `on_response_headers`, or `on_response_body` must be specified. + """ + + fetch_compressed: Optional[OptionsFetchCompressed] + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress + your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or + `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If + you enable it in CDN resource and want to use `gzipON` and + `brotli_compression` in a rule, you have to specify + `"fetch_compressed": false` in the rule. + """ + + follow_origin_redirect: Optional[OptionsFollowOriginRedirect] + """ + Enables redirection from origin. If the origin server returns a redirect, the + option allows the CDN to pull the requested content from the origin server that + was returned in the redirect. + """ + + force_return: Optional[OptionsForceReturn] + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this + option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + forward_host_header: Optional[OptionsForwardHostHeader] + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + gzip_on: Annotated[Optional[OptionsGzipOn], PropertyInfo(alias="gzipOn")] + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` + options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in + rules. If you enable `fetch_compressed` in CDN resource and want to enable + `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + host_header: Annotated[Optional[OptionsHostHeader], PropertyInfo(alias="hostHeader")] + """ + Sets the Host header that CDN servers use when request content from an origin + server. Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + http3_enabled: Optional[OptionsHttp3Enabled] + """Enables HTTP/3 protocol for content delivery. + + `http3_enabled` option works only with `"sslEnabled": true`. + """ + + ignore_cookie: Optional[OptionsIgnoreCookie] + """ + Defines whether the files with the Set-Cookies header are cached as one file or + as different ones. + """ + + ignore_query_string: Annotated[Optional[OptionsIgnoreQueryString], PropertyInfo(alias="ignoreQueryString")] + """ + How a file with different query strings is cached: either as one object (option + is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + image_stack: Optional[OptionsImageStack] + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically + converts them to WebP or AVIF format. + """ + + ip_address_acl: Optional[OptionsIPAddressACL] + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, + you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. + [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + limit_bandwidth: Optional[OptionsLimitBandwidth] + """Allows to control the download speed per connection.""" + + proxy_cache_key: Optional[OptionsProxyCacheKey] + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache + and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will + not work. + """ + + proxy_cache_methods_set: Optional[OptionsProxyCacheMethodsSet] + """Caching for POST requests along with default GET and HEAD.""" + + proxy_connect_timeout: Optional[OptionsProxyConnectTimeout] + """The time limit for establishing a connection with the origin.""" + + proxy_read_timeout: Optional[OptionsProxyReadTimeout] + """ + The time limit for receiving a partial response from the origin. If no response + is received within this time, the connection will be closed. + + **Note:** When used with a WebSocket connection, this option supports values + only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + query_params_blacklist: Optional[OptionsQueryParamsBlacklist] + """ + Files with the specified query parameters are cached as one object, files with + other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_params_whitelist: Optional[OptionsQueryParamsWhitelist] + """ + Files with the specified query parameters are cached as different objects, files + with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_string_forwarding: Optional[OptionsQueryStringForwarding] + """ + The Query String Forwarding feature allows for the seamless transfer of + parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication + tokens or tracking information, are consistently passed along from the playlist + manifest to the individual media segments. This is particularly useful for + maintaining continuity in security, analytics, and any other parameter-based + operations across the entire media delivery workflow. + """ + + redirect_http_to_https: Optional[OptionsRedirectHTTPToHTTPS] + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + redirect_https_to_http: Optional[OptionsRedirectHTTPSToHTTP] + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + referrer_acl: Optional[OptionsReferrerACL] + """Controls access to the CDN resource content for specified domain names.""" + + request_limiter: Optional[OptionsRequestLimiter] + """Option allows to limit the amount of HTTP requests.""" + + response_headers_hiding_policy: Optional[OptionsResponseHeadersHidingPolicy] + """Hides HTTP headers from an origin server in the CDN response.""" + + rewrite: Optional[OptionsRewrite] + """Changes and redirects requests from the CDN to the origin. + + It operates according to the + [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) + configuration. + """ + + secure_key: Optional[OptionsSecureKey] + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + slice: Optional[OptionsSlice] + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per + part.) This reduces time to first byte. + + The option is based on the + [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` + options enabled. + """ + + sni: Optional[OptionsSni] + """ + The hostname that is added to SNI requests from CDN servers to the origin server + via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not + have a dedicated IP address. If the origin server presents multiple + certificates, SNI allows the origin server to know which certificate to use for + the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + stale: Optional[OptionsStale] + """Serves stale cached content in case of origin unavailability.""" + + static_response_headers: Optional[OptionsStaticResponseHeaders] + """Custom HTTP Headers that a CDN server adds to a response.""" + + static_headers: Annotated[Optional[OptionsStaticHeaders], PropertyInfo(alias="staticHeaders")] + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP + Headers can be specified. May contain a header with multiple values. + """ + + static_request_headers: Annotated[Optional[OptionsStaticRequestHeaders], PropertyInfo(alias="staticRequestHeaders")] + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + tls_versions: Optional[OptionsTlsVersions] + """ + List of SSL/TLS protocol versions allowed for HTTPS connections from end users + to the domain. + + When the option is disabled, all protocols versions are allowed. + """ + + use_default_le_chain: Optional[OptionsUseDefaultLeChain] + """Let's Encrypt certificate chain. + + The specified chain will be used during the next Let's Encrypt certificate issue + or renewal. + """ + + use_dns01_le_challenge: Optional[OptionsUseDns01LeChallenge] + """DNS-01 challenge to issue a Let's Encrypt certificate for the resource. + + DNS service should be activated to enable this option. + """ + + use_rsa_le_cert: Optional[OptionsUseRsaLeCert] + """RSA Let's Encrypt certificate type for the CDN resource. + + The specified value will be used during the next Let's Encrypt certificate issue + or renewal. + """ + + user_agent_acl: Optional[OptionsUserAgentACL] + """Controls access to the content for specified User-Agents.""" + + waap: Optional[OptionsWaap] + """Allows to enable WAAP (Web Application and API Protection).""" + + websockets: Optional[OptionsWebsockets] + """Enables or disables WebSockets connections to an origin server.""" diff --git a/src/gcore/types/cdn/cdn_resource_list.py b/src/gcore/types/cdn/cdn_resource_list.py new file mode 100644 index 00000000..8146c2e7 --- /dev/null +++ b/src/gcore/types/cdn/cdn_resource_list.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .cdn_resource import CDNResource + +__all__ = ["CDNResourceList"] + +CDNResourceList: TypeAlias = List[CDNResource] diff --git a/src/gcore/types/cdn/cdn_resource_list_params.py b/src/gcore/types/cdn/cdn_resource_list_params.py new file mode 100644 index 00000000..98c70e08 --- /dev/null +++ b/src/gcore/types/cdn/cdn_resource_list_params.py @@ -0,0 +1,107 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["CDNResourceListParams"] + + +class CDNResourceListParams(TypedDict, total=False): + cname: str + """Delivery domain (CNAME) of the CDN resource.""" + + deleted: bool + """Defines whether a CDN resource has been deleted. + + Possible values: + + - **true** - CDN resource has been deleted. + - **false** - CDN resource has not been deleted. + """ + + enabled: bool + """Enables or disables a CDN resource change by a user. + + Possible values: + + - **true** - CDN resource is enabled. + - **false** - CDN resource is disabled. + """ + + max_created: str + """ + Most recent date of CDN resource creation for which CDN resources should be + returned (ISO 8601/RFC 3339 format, UTC.) + """ + + min_created: str + """ + Earliest date of CDN resource creation for which CDN resources should be + returned (ISO 8601/RFC 3339 format, UTC.) + """ + + origin_group: Annotated[int, PropertyInfo(alias="originGroup")] + """Origin group ID.""" + + rules: str + """Rule name or pattern.""" + + secondary_hostnames: Annotated[str, PropertyInfo(alias="secondaryHostnames")] + """Additional delivery domains (CNAMEs) of the CDN resource.""" + + shield_dc: str + """Name of the origin shielding data center location.""" + + shielded: bool + """Defines whether origin shielding is enabled for the CDN resource. + + Possible values: + + - **true** - Origin shielding is enabled for the CDN resource. + - **false** - Origin shielding is disabled for the CDN resource. + """ + + ssl_data: Annotated[int, PropertyInfo(alias="sslData")] + """SSL certificate ID.""" + + ssl_data_in: Annotated[int, PropertyInfo(alias="sslData_in")] + """SSL certificates IDs. + + Example: + + - ?`sslData_in`=1643,1644,1652 + """ + + ssl_enabled: Annotated[bool, PropertyInfo(alias="sslEnabled")] + """Defines whether the HTTPS protocol is enabled for content delivery. + + Possible values: + + - **true** - HTTPS protocol is enabled for CDN resource. + - **false** - HTTPS protocol is disabled for CDN resource. + """ + + status: Literal["active", "processed", "suspended", "deleted"] + """CDN resource status.""" + + suspend: bool + """Defines whether the CDN resource was automatically suspended by the system. + + Possible values: + + - **true** - CDN resource is selected for automatic suspension in the next 7 + days. + - **false** - CDN resource is not selected for automatic suspension. + """ + + vp_enabled: bool + """Defines whether the CDN resource is integrated with the Streaming platform. + + Possible values: + + - **true** - CDN resource is used for Streaming platform. + - **false** - CDN resource is not used for Streaming platform. + """ diff --git a/src/gcore/types/cdn/cdn_resource_prefetch_params.py b/src/gcore/types/cdn/cdn_resource_prefetch_params.py new file mode 100644 index 00000000..1d3c0aa0 --- /dev/null +++ b/src/gcore/types/cdn/cdn_resource_prefetch_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["CDNResourcePrefetchParams"] + + +class CDNResourcePrefetchParams(TypedDict, total=False): + paths: Required[SequenceNotStr[str]] + """Paths to files that should be pre-populated to the CDN. + + Paths to the files should be specified without a domain name. + """ diff --git a/src/gcore/types/cdn/cdn_resource_purge_params.py b/src/gcore/types/cdn/cdn_resource_purge_params.py new file mode 100644 index 00000000..aa885a05 --- /dev/null +++ b/src/gcore/types/cdn/cdn_resource_purge_params.py @@ -0,0 +1,71 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import TypeAlias, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["CDNResourcePurgeParams", "PurgeByURL", "PurgeByPattern", "PurgeAllCache"] + + +class PurgeByURL(TypedDict, total=False): + urls: SequenceNotStr[str] + """**Purge by URL** clears the cache of a specific files. + + This purge type is recommended. + + Specify file URLs including query strings. URLs should start with / without a + domain name. + + Purge by URL depends on the following CDN options: + + 1. "vary response header" is used. If your origin serves variants of the same + content depending on the Vary HTTP response header, purge by URL will delete + only one version of the file. + 2. "slice" is used. If you update several files in the origin without clearing + the CDN cache, purge by URL will delete only the first slice (with bytes=0… + .) + 3. "ignoreQueryString" is used. Don’t specify parameters in the purge request. + 4. "query_params_blacklist" is used. Only files with the listed in the option + parameters will be cached as different objects. Files with other parameters + will be cached as one object. In this case, specify the listed parameters in + the Purge request. Don't specify other parameters. + 5. "query_params_whitelist" is used. Files with listed in the option parameters + will be cached as one object. Files with other parameters will be cached as + different objects. In this case, specify other parameters (if any) besides + the ones listed in the purge request. + """ + + +class PurgeByPattern(TypedDict, total=False): + paths: SequenceNotStr[str] + """**Purge by pattern** clears the cache that matches the pattern. + + Use _ operator, which replaces any number of symbols in your path. It's + important to note that wildcard usage (_) is permitted only at the end of a + pattern. + + Query string added to any patterns will be ignored, and purge request will be + processed as if there weren't any parameters. + + Purge by pattern is recursive. Both /path and /path* will result in recursive + purging, meaning all content under the specified path will be affected. As such, + using the pattern /path* is functionally equivalent to simply using /path. + """ + + +class PurgeAllCache(TypedDict, total=False): + paths: SequenceNotStr[str] + """**Purge all cache** clears the entire cache for the CDN resource. + + Specify an empty array to purge all content for the resource. + + When you purge all assets, CDN servers request content from your origin server + and cause a high load. Therefore, we recommend to use purge by URL for large + content quantities. + """ + + +CDNResourcePurgeParams: TypeAlias = Union[PurgeByURL, PurgeByPattern, PurgeAllCache] diff --git a/src/gcore/types/cdn/cdn_resource_replace_params.py b/src/gcore/types/cdn/cdn_resource_replace_params.py new file mode 100644 index 00000000..352ca804 --- /dev/null +++ b/src/gcore/types/cdn/cdn_resource_replace_params.py @@ -0,0 +1,2114 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable, Optional +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = [ + "CDNResourceReplaceParams", + "Options", + "OptionsAllowedHTTPMethods", + "OptionsBotProtection", + "OptionsBotProtectionBotChallenge", + "OptionsBrotliCompression", + "OptionsBrowserCacheSettings", + "OptionsCacheHTTPHeaders", + "OptionsCors", + "OptionsCountryACL", + "OptionsDisableCache", + "OptionsDisableProxyForceRanges", + "OptionsEdgeCacheSettings", + "OptionsFastedge", + "OptionsFastedgeOnRequestBody", + "OptionsFastedgeOnRequestHeaders", + "OptionsFastedgeOnResponseBody", + "OptionsFastedgeOnResponseHeaders", + "OptionsFetchCompressed", + "OptionsFollowOriginRedirect", + "OptionsForceReturn", + "OptionsForceReturnTimeInterval", + "OptionsForwardHostHeader", + "OptionsGzipOn", + "OptionsHostHeader", + "OptionsHttp3Enabled", + "OptionsIgnoreCookie", + "OptionsIgnoreQueryString", + "OptionsImageStack", + "OptionsIPAddressACL", + "OptionsLimitBandwidth", + "OptionsProxyCacheKey", + "OptionsProxyCacheMethodsSet", + "OptionsProxyConnectTimeout", + "OptionsProxyReadTimeout", + "OptionsQueryParamsBlacklist", + "OptionsQueryParamsWhitelist", + "OptionsQueryStringForwarding", + "OptionsRedirectHTTPToHTTPS", + "OptionsRedirectHTTPSToHTTP", + "OptionsReferrerACL", + "OptionsRequestLimiter", + "OptionsResponseHeadersHidingPolicy", + "OptionsRewrite", + "OptionsSecureKey", + "OptionsSlice", + "OptionsSni", + "OptionsStale", + "OptionsStaticResponseHeaders", + "OptionsStaticResponseHeadersValue", + "OptionsStaticHeaders", + "OptionsStaticRequestHeaders", + "OptionsTlsVersions", + "OptionsUseDefaultLeChain", + "OptionsUseDns01LeChallenge", + "OptionsUseRsaLeCert", + "OptionsUserAgentACL", + "OptionsWaap", + "OptionsWebsockets", +] + + +class CDNResourceReplaceParams(TypedDict, total=False): + origin_group: Required[Annotated[int, PropertyInfo(alias="originGroup")]] + """Origin group ID with which the CDN resource is associated.""" + + active: bool + """Enables or disables a CDN resource. + + Possible values: + + - **true** - CDN resource is active. Content is being delivered. + - **false** - CDN resource is deactivated. Content is not being delivered. + """ + + description: str + """Optional comment describing the CDN resource.""" + + name: Optional[str] + """CDN resource name.""" + + options: Options + """List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. Option may + inherit its value from the global account settings. + """ + + origin_protocol: Annotated[Literal["HTTP", "HTTPS", "MATCH"], PropertyInfo(alias="originProtocol")] + """Protocol used by CDN servers to request content from an origin source. + + Possible values: + + - **HTTPS** - CDN servers will connect to the origin via HTTPS. + - **HTTP** - CDN servers will connect to the origin via HTTP. + - **MATCH** - connection protocol will be chosen automatically (content on the + origin source should be available for the CDN both through HTTP and HTTPS). + + If protocol is not specified, HTTP is used to connect to an origin server. + """ + + proxy_ssl_ca: Optional[int] + """ID of the trusted CA certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + """ + + proxy_ssl_data: Optional[int] + """ID of the SSL certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + """ + + proxy_ssl_enabled: bool + """ + Enables or disables SSL certificate validation of the origin server before + completing any connection. + + Possible values: + + - **true** - Origin SSL certificate validation is enabled. + - **false** - Origin SSL certificate validation is disabled. + """ + + secondary_hostnames: Annotated[SequenceNotStr[str], PropertyInfo(alias="secondaryHostnames")] + """ + Additional delivery domains (CNAMEs) that will be used to deliver content via + the CDN. + + Up to ten additional CNAMEs are possible. + """ + + ssl_data: Annotated[Optional[int], PropertyInfo(alias="sslData")] + """ID of the SSL certificate linked to the CDN resource. + + Can be used only with `"sslEnabled": true`. + """ + + ssl_enabled: Annotated[bool, PropertyInfo(alias="sslEnabled")] + """Defines whether the HTTPS protocol enabled for content delivery. + + Possible values: + + - **true** - HTTPS is enabled. + - **false** - HTTPS is disabled. + """ + + waap_api_domain_enabled: bool + """Defines whether the associated WAAP Domain is identified as an API Domain. + + Possible values: + + - **true** - The associated WAAP Domain is designated as an API Domain. + - **false** - The associated WAAP Domain is not designated as an API Domain. + """ + + +class OptionsAllowedHTTPMethods(TypedDict, total=False): + """HTTP methods allowed for content requests from the CDN.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[List[Literal["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]]] + + +class OptionsBotProtectionBotChallenge(TypedDict, total=False): + """Controls the bot challenge module state.""" + + enabled: bool + """Possible values: + + - **true** - Bot challenge is enabled. + - **false** - Bot challenge is disabled. + """ + + +class OptionsBotProtection(TypedDict, total=False): + """ + Allows to prevent online services from overloading and ensure your business workflow running smoothly. + """ + + bot_challenge: Required[OptionsBotProtectionBotChallenge] + """Controls the bot challenge module state.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsBrotliCompression(TypedDict, total=False): + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN resource and want to enable `brotli_compression` in a rule, you must specify `fetch_compressed:false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "application/javascript", + "application/json", + "application/vnd.ms-fontobject", + "application/wasm", + "application/x-font-ttf", + "application/x-javascript", + "application/xml", + "application/xml+rss", + "image/svg+xml", + "image/x-icon", + "text/css", + "text/html", + "text/javascript", + "text/plain", + "text/xml", + ] + ] + ] + """Allows to select the content types you want to compress. + + `text/html` is a mandatory content type. + """ + + +class OptionsBrowserCacheSettings(TypedDict, total=False): + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Set the cache expiration time to '0s' to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsCacheHTTPHeaders(TypedDict, total=False): + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + + +class OptionsCors(TypedDict, total=False): + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header to a response to a browser. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """Value of the Access-Control-Allow-Origin header. + + Possible values: + + - **Adds \\** as the Access-Control-Allow-Origin header value** - Content will be + uploaded for requests from any domain. `"value": ["*"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value if the + origin matches one of the listed domains** - Content will be uploaded only for + requests from the domains specified in the field. + `"value": ["domain.com", "second.dom.com"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value** - + Content will be uploaded for requests from any domain, and the domain from + which the request was sent will be added to the "Access-Control-Allow-Origin" + header in the response. `"value": ["$http_origin"]` + """ + + always: bool + """ + Defines whether the Access-Control-Allow-Origin header should be added to a + response from CDN regardless of response code. + + Possible values: + + - **true** - Header will be added to a response regardless of response code. + - **false** - Header will only be added to responses with codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsCountryACL(TypedDict, total=False): + """Enables control access to content for specified countries.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of countries according to ISO-3166-1. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of countries for which access is prohibited. + - **deny** - List of countries for which access is allowed. + """ + + policy_type: Required[Literal["allow", "deny"]] + """Defines the type of CDN resource access policy. + + Possible values: + + - **allow** - Access is allowed for all the countries except for those specified + in `excepted_values` field. + - **deny** - Access is denied for all the countries except for those specified + in `excepted_values` field. + """ + + +class OptionsDisableCache(TypedDict, total=False): + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - content caching is disabled. + - **false** - content caching is enabled. + """ + + +class OptionsDisableProxyForceRanges(TypedDict, total=False): + """Allows 206 responses regardless of the settings of an origin source.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsEdgeCacheSettings(TypedDict, total=False): + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + custom_values: Dict[str, str] + """ + A MAP object representing the caching time in seconds for a response with a + specific response code. + + These settings have a higher priority than the `value` field. + + - Use `any` key to specify caching time for all response codes. + - Use `0s` value to disable caching for a specific response code. + """ + + default: str + """Enables content caching according to the origin cache settings. + + The value is applied to the following response codes 200, 201, 204, 206, 301, + 302, 303, 304, 307, 308, if an origin server does not have caching HTTP headers. + + Responses with other codes will not be cached. + + The maximum duration is any equivalent to `1y`. + """ + + value: str + """Caching time. + + The value is applied to the following response codes: 200, 206, 301, 302. + Responses with codes 4xx, 5xx will not be cached. + + Use `0s` to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsFastedgeOnRequestBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request body as soon as CDN receives incoming HTTP request. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnRequestHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response body before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response headers before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedge(TypedDict, total=False): + """ + Allows to configure FastEdge app to be called on different request/response phases. + + Note: At least one of `on_request_headers`, `on_request_body`, `on_response_headers`, or `on_response_body` must be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + on_request_body: OptionsFastedgeOnRequestBody + """ + Allows to configure FastEdge application that will be called to handle request + body as soon as CDN receives incoming HTTP request. + """ + + on_request_headers: OptionsFastedgeOnRequestHeaders + """ + Allows to configure FastEdge application that will be called to handle request + headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + on_response_body: OptionsFastedgeOnResponseBody + """ + Allows to configure FastEdge application that will be called to handle response + body before CDN sends the HTTP response. + """ + + on_response_headers: OptionsFastedgeOnResponseHeaders + """ + Allows to configure FastEdge application that will be called to handle response + headers before CDN sends the HTTP response. + """ + + +class OptionsFetchCompressed(TypedDict, total=False): + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If you enable it in CDN resource and want to use `gzipON` and `brotli_compression` in a rule, you have to specify `"fetch_compressed": false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsFollowOriginRedirect(TypedDict, total=False): + """ + Enables redirection from origin. + If the origin server returns a redirect, the option allows the CDN to pull the requested content from the origin server that was returned in the redirect. + """ + + codes: Required[Iterable[Literal[301, 302, 303, 307, 308]]] + """Redirect status code that the origin server returns. + + To serve up to date content to end users, you will need to purge the cache after + managing the option. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsForceReturnTimeInterval(TypedDict, total=False): + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + end_time: Required[str] + """Time until which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + start_time: Required[str] + """Time from which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + time_zone: str + """Time zone used to calculate time.""" + + +class OptionsForceReturn(TypedDict, total=False): + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + body: Required[str] + """URL for redirection or text.""" + + code: Required[int] + """Status code value.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + time_interval: Optional[OptionsForceReturnTimeInterval] + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + +class OptionsForwardHostHeader(TypedDict, total=False): + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsGzipOn(TypedDict, total=False): + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in rules. If you enable `fetch_compressed` in CDN resource and want to enable `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsHostHeader(TypedDict, total=False): + """ + Sets the Host header that CDN servers use when request content from an origin server. + Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Host Header value.""" + + +class OptionsHttp3Enabled(TypedDict, total=False): + """Enables HTTP/3 protocol for content delivery. + + `http3_enabled` option works only with `"sslEnabled": true`. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsIgnoreCookie(TypedDict, total=False): + """ + Defines whether the files with the Set-Cookies header are cached as one file or as different ones. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled, files with cookies are cached as one file. + - **false** - Option is disabled, files with cookies are cached as different + files. + """ + + +class OptionsIgnoreQueryString(TypedDict, total=False): + """ + How a file with different query strings is cached: either as one object (option is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsImageStack(TypedDict, total=False): + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically converts them to WebP or AVIF format. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + avif_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to AVI format.""" + + png_lossless: bool + """Enables or disables compression without quality loss for PNG format.""" + + quality: int + """Defines quality settings for JPG and PNG images. + + The higher the value, the better the image quality, and the larger the file size + after conversion. + """ + + webp_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to WebP format.""" + + +class OptionsIPAddressACL(TypedDict, total=False): + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of IP addresses with a subnet mask. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of IP addresses for which access is prohibited. + - **deny** - List of IP addresses for which access is allowed. + + Examples: + + - `192.168.3.2/32` + - `2a03:d000:2980:7::8/128` + """ + + policy_type: Required[Literal["allow", "deny"]] + """IP access policy type. + + Possible values: + + - **allow** - Allow access to all IPs except IPs specified in "excepted_values" + field. + - **deny** - Deny access to all IPs except IPs specified in "excepted_values" + field. + """ + + +class OptionsLimitBandwidth(TypedDict, total=False): + """Allows to control the download speed per connection.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + limit_type: Required[Literal["static", "dynamic"]] + """Method of controlling the download speed per connection. + + Possible values: + + - **static** - Use speed and buffer fields to set the download speed limit. + - **dynamic** - Use query strings **speed** and **buffer** to set the download + speed limit. + + For example, when requesting content at the link + + ``` + http://cdn.example.com/video.mp4?speed=50k&buffer=500k + ``` + + the download speed will be limited to 50kB/s after 500 kB. + """ + + buffer: int + """Amount of downloaded data after which the user will be rate limited.""" + + speed: int + """Maximum download speed per connection.""" + + +class OptionsProxyCacheKey(TypedDict, total=False): + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will not work. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Key for caching.""" + + +class OptionsProxyCacheMethodsSet(TypedDict, total=False): + """Caching for POST requests along with default GET and HEAD.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsProxyConnectTimeout(TypedDict, total=False): + """The time limit for establishing a connection with the origin.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 5s**. + """ + + +class OptionsProxyReadTimeout(TypedDict, total=False): + """ + The time limit for receiving a partial response from the origin. + If no response is received within this time, the connection will be closed. + + **Note:** + When used with a WebSocket connection, this option supports values only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 30s**. + """ + + +class OptionsQueryParamsBlacklist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as one object, files with other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryParamsWhitelist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as different objects, files with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryStringForwarding(TypedDict, total=False): + """ + The Query String Forwarding feature allows for the seamless transfer of parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication tokens or tracking information, are consistently passed along from the playlist manifest to the individual media segments. + This is particularly useful for maintaining continuity in security, analytics, and any other parameter-based operations across the entire media delivery workflow. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + forward_from_file_types: Required[SequenceNotStr[str]] + """ + The `forward_from_files_types` field specifies the types of playlist files from + which parameters will be extracted and forwarded. This typically includes + formats that list multiple media chunk references, such as HLS and DASH + playlists. Parameters associated with these playlist files (like query strings + or headers) will be propagated to the chunks they reference. + """ + + forward_to_file_types: Required[SequenceNotStr[str]] + """ + The field specifies the types of media chunk files to which parameters, + extracted from playlist files, will be forwarded. These refer to the actual + segments of media content that are delivered to viewers. Ensuring the correct + parameters are forwarded to these files is crucial for maintaining the integrity + of the streaming session. + """ + + forward_except_keys: SequenceNotStr[str] + """ + The `forward_except_keys` field provides a mechanism to exclude specific + parameters from being forwarded from playlist files to media chunk files. By + listing certain keys in this field, you can ensure that these parameters are + omitted during the forwarding process. This is particularly useful for + preventing sensitive or irrelevant information from being included in requests + for media chunks, thereby enhancing security and optimizing performance. + """ + + forward_only_keys: SequenceNotStr[str] + """ + The `forward_only_keys` field allows for granular control over which specific + parameters are forwarded from playlist files to media chunk files. By specifying + certain keys, only those parameters will be propagated, ensuring that only + relevant information is passed along. This is particularly useful for security + and performance optimization, as it prevents unnecessary or sensitive data from + being included in requests for media chunks. + """ + + +class OptionsRedirectHTTPToHTTPS(TypedDict, total=False): + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsRedirectHTTPSToHTTP(TypedDict, total=False): + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsReferrerACL(TypedDict, total=False): + """Controls access to the CDN resource content for specified domain names.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """ + List of domain names or wildcard domains (without protocol: `http://` or + `https://`.) + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of domain names for which access is prohibited. + - **deny** - List of IP domain names for which access is allowed. + + Examples: + + - `example.com` + - `*.example.com` + """ + + policy_type: Required[Literal["allow", "deny"]] + """Policy type. + + Possible values: + + - **allow** - Allow access to all domain names except the domain names specified + in `excepted_values` field. + - **deny** - Deny access to all domain names except the domain names specified + in `excepted_values` field. + """ + + +class OptionsRequestLimiter(TypedDict, total=False): + """Option allows to limit the amount of HTTP requests.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + rate: Required[int] + """Maximum request rate.""" + + rate_unit: Literal["r/s", "r/m"] + """Units of measurement for the `rate` field. + + Possible values: + + - **r/s** - Requests per second. + - **r/m** - Requests per minute. + + If the rate is less than one request per second, it is specified in request per + minute (r/m.) + """ + + +class OptionsResponseHeadersHidingPolicy(TypedDict, total=False): + """Hides HTTP headers from an origin server in the CDN response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted: Required[SequenceNotStr[str]] + """List of HTTP headers. + + Parameter meaning depends on the value of the `mode` field: + + - **show** - List of HTTP headers to hide from response. + - **hide** - List of HTTP headers to include in response. Other HTTP headers + will be hidden. + + The following headers are required and cannot be hidden from response: + + - `Connection` + - `Content-Length` + - `Content-Type` + - `Date` + - `Server` + """ + + mode: Required[Literal["hide", "show"]] + """How HTTP headers are hidden from the response. + + Possible values: + + - **show** - Hide only HTTP headers listed in the `excepted` field. + - **hide** - Hide all HTTP headers except headers listed in the "excepted" + field. + """ + + +class OptionsRewrite(TypedDict, total=False): + """Changes and redirects requests from the CDN to the origin. + + It operates according to the [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) configuration. + """ + + body: Required[str] + """Path for the Rewrite option. + + Example: + + - `/(.*) /media/$1` + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + flag: Literal["break", "last", "redirect", "permanent"] + """Flag for the Rewrite option. + + Possible values: + + - **last** - Stop processing the current set of `ngx_http_rewrite_module` + directives and start a search for a new location matching changed URI. + - **break** - Stop processing the current set of the Rewrite option. + - **redirect** - Return a temporary redirect with the 302 code; used when a + replacement string does not start with `http://`, `https://`, or `$scheme`. + - **permanent** - Return a permanent redirect with the 301 code. + """ + + +class OptionsSecureKey(TypedDict, total=False): + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + key: Required[Optional[str]] + """Key generated on your side that will be used for URL signing.""" + + type: Literal[0, 2] + """Type of URL signing. + + Possible types: + + - **Type 0** - Includes end user IP to secure token generation. + - **Type 2** - Excludes end user IP from secure token generation. + """ + + +class OptionsSlice(TypedDict, total=False): + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per part.) This reduces time to first byte. + + The option is based on the [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` options enabled. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsSni(TypedDict, total=False): + """ + The hostname that is added to SNI requests from CDN servers to the origin server via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not have a dedicated IP address. + If the origin server presents multiple certificates, SNI allows the origin server to know which certificate to use for the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + custom_hostname: Required[str] + """Custom SNI hostname. + + It is required if `sni_type` is set to custom. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + sni_type: Literal["dynamic", "custom"] + """SNI (Server Name Indication) type. + + Possible values: + + - **dynamic** - SNI hostname depends on `hostHeader` and `forward_host_header` + options. It has several possible combinations: + - If the `hostHeader` option is enabled and specified, SNI hostname matches the + Host header. + - If the `forward_host_header` option is enabled and has true value, SNI + hostname matches the Host header used in the request made to a CDN. + - If the `hostHeader` and `forward_host_header` options are disabled, SNI + hostname matches the primary CNAME. + - **custom** - custom SNI hostname is in use. + """ + + +class OptionsStale(TypedDict, total=False): + """Serves stale cached content in case of origin unavailability.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "error", + "http_403", + "http_404", + "http_429", + "http_500", + "http_502", + "http_503", + "http_504", + "invalid_header", + "timeout", + "updating", + ] + ] + ] + """Defines list of errors for which "Always online" option is applied.""" + + +class OptionsStaticResponseHeadersValue(TypedDict, total=False): + name: Required[str] + """HTTP Header name. + + Restrictions: + + - Maximum 128 symbols. + - Latin letters (A-Z, a-z,) numbers (0-9,) dashes, and underscores only. + """ + + value: Required[SequenceNotStr[str]] + """Header value. + + Restrictions: + + - Maximum 512 symbols. + - Letters (a-z), numbers (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ + /|\";:?.,><{}[]). + - Must start with a letter, number, asterisk or {. + - Multiple values can be added. + """ + + always: bool + """ + Defines whether the header will be added to a response from CDN regardless of + response code. + + Possible values: + + - **true** - Header will be added to a response from CDN regardless of response + code. + - **false** - Header will be added only to the following response codes: 200, + 201, 204, 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsStaticResponseHeaders(TypedDict, total=False): + """Custom HTTP Headers that a CDN server adds to a response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Iterable[OptionsStaticResponseHeadersValue]] + + +class OptionsStaticHeaders(TypedDict, total=False): + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP Headers can be specified. May contain a header with multiple values. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[object] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 128 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsStaticRequestHeaders(TypedDict, total=False): + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Dict[str, str]] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 255 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsTlsVersions(TypedDict, total=False): + """ + List of SSL/TLS protocol versions allowed for HTTPS connections from end users to the domain. + + When the option is disabled, all protocols versions are allowed. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[List[Literal["SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"]]] + """List of SSL/TLS protocol versions (case sensitive).""" + + +class OptionsUseDefaultLeChain(TypedDict, total=False): + """Let's Encrypt certificate chain. + + The specified chain will be used during the next Let's Encrypt certificate issue or renewal. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Default Let's Encrypt certificate chain. This is a deprecated + version, use it only for compatibilities with Android devices 7.1.1 or lower. + - **false** - Alternative Let's Encrypt certificate chain. + """ + + +class OptionsUseDns01LeChallenge(TypedDict, total=False): + """DNS-01 challenge to issue a Let's Encrypt certificate for the resource. + + DNS service should be activated to enable this option. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - DNS-01 challenge is used to issue Let's Encrypt certificate. + - **false** - HTTP-01 challenge is used to issue Let's Encrypt certificate. + """ + + +class OptionsUseRsaLeCert(TypedDict, total=False): + """RSA Let's Encrypt certificate type for the CDN resource. + + The specified value will be used during the next Let's Encrypt certificate issue or renewal. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - RSA Let's Encrypt certificate. + - **false** - ECDSA Let's Encrypt certificate. + """ + + +class OptionsUserAgentACL(TypedDict, total=False): + """Controls access to the content for specified User-Agents.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of User-Agents that will be allowed/denied. + + The meaning of the parameter depends on `policy_type`: + + - **allow** - List of User-Agents for which access is prohibited. + - **deny** - List of User-Agents for which access is allowed. + + You can provide exact User-Agent strings or regular expressions. Regular + expressions must start with `~` (case-sensitive) or `~*` (case-insensitive). + + Use an empty string `""` to allow/deny access when the User-Agent header is + empty. + """ + + policy_type: Required[Literal["allow", "deny"]] + """User-Agents policy type. + + Possible values: + + - **allow** - Allow access for all User-Agents except specified in + `excepted_values` field. + - **deny** - Deny access for all User-Agents except specified in + `excepted_values` field. + """ + + +class OptionsWaap(TypedDict, total=False): + """Allows to enable WAAP (Web Application and API Protection).""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsWebsockets(TypedDict, total=False): + """Enables or disables WebSockets connections to an origin server.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class Options(TypedDict, total=False): + """List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. + Option may inherit its value from the global account settings. + """ + + allowed_http_methods: Annotated[Optional[OptionsAllowedHTTPMethods], PropertyInfo(alias="allowedHttpMethods")] + """HTTP methods allowed for content requests from the CDN.""" + + bot_protection: Optional[OptionsBotProtection] + """ + Allows to prevent online services from overloading and ensure your business + workflow running smoothly. + """ + + brotli_compression: Optional[OptionsBrotliCompression] + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is + activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, + even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` + options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides + `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN + resource and want to enable `brotli_compression` in a rule, you must specify + `fetch_compressed:false` in the rule. + """ + + browser_cache_settings: Optional[OptionsBrowserCacheSettings] + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + cache_http_headers: Optional[OptionsCacheHTTPHeaders] + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + cors: Optional[OptionsCors] + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header + to a response to a browser. + """ + + country_acl: Optional[OptionsCountryACL] + """Enables control access to content for specified countries.""" + + disable_cache: Optional[OptionsDisableCache] + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + disable_proxy_force_ranges: Optional[OptionsDisableProxyForceRanges] + """Allows 206 responses regardless of the settings of an origin source.""" + + edge_cache_settings: Optional[OptionsEdgeCacheSettings] + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + fastedge: Optional[OptionsFastedge] + """ + Allows to configure FastEdge app to be called on different request/response + phases. + + Note: At least one of `on_request_headers`, `on_request_body`, + `on_response_headers`, or `on_response_body` must be specified. + """ + + fetch_compressed: Optional[OptionsFetchCompressed] + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress + your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or + `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If + you enable it in CDN resource and want to use `gzipON` and + `brotli_compression` in a rule, you have to specify + `"fetch_compressed": false` in the rule. + """ + + follow_origin_redirect: Optional[OptionsFollowOriginRedirect] + """ + Enables redirection from origin. If the origin server returns a redirect, the + option allows the CDN to pull the requested content from the origin server that + was returned in the redirect. + """ + + force_return: Optional[OptionsForceReturn] + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this + option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + forward_host_header: Optional[OptionsForwardHostHeader] + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + gzip_on: Annotated[Optional[OptionsGzipOn], PropertyInfo(alias="gzipOn")] + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` + options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in + rules. If you enable `fetch_compressed` in CDN resource and want to enable + `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + host_header: Annotated[Optional[OptionsHostHeader], PropertyInfo(alias="hostHeader")] + """ + Sets the Host header that CDN servers use when request content from an origin + server. Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + http3_enabled: Optional[OptionsHttp3Enabled] + """Enables HTTP/3 protocol for content delivery. + + `http3_enabled` option works only with `"sslEnabled": true`. + """ + + ignore_cookie: Optional[OptionsIgnoreCookie] + """ + Defines whether the files with the Set-Cookies header are cached as one file or + as different ones. + """ + + ignore_query_string: Annotated[Optional[OptionsIgnoreQueryString], PropertyInfo(alias="ignoreQueryString")] + """ + How a file with different query strings is cached: either as one object (option + is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + image_stack: Optional[OptionsImageStack] + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically + converts them to WebP or AVIF format. + """ + + ip_address_acl: Optional[OptionsIPAddressACL] + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, + you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. + [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + limit_bandwidth: Optional[OptionsLimitBandwidth] + """Allows to control the download speed per connection.""" + + proxy_cache_key: Optional[OptionsProxyCacheKey] + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache + and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will + not work. + """ + + proxy_cache_methods_set: Optional[OptionsProxyCacheMethodsSet] + """Caching for POST requests along with default GET and HEAD.""" + + proxy_connect_timeout: Optional[OptionsProxyConnectTimeout] + """The time limit for establishing a connection with the origin.""" + + proxy_read_timeout: Optional[OptionsProxyReadTimeout] + """ + The time limit for receiving a partial response from the origin. If no response + is received within this time, the connection will be closed. + + **Note:** When used with a WebSocket connection, this option supports values + only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + query_params_blacklist: Optional[OptionsQueryParamsBlacklist] + """ + Files with the specified query parameters are cached as one object, files with + other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_params_whitelist: Optional[OptionsQueryParamsWhitelist] + """ + Files with the specified query parameters are cached as different objects, files + with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_string_forwarding: Optional[OptionsQueryStringForwarding] + """ + The Query String Forwarding feature allows for the seamless transfer of + parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication + tokens or tracking information, are consistently passed along from the playlist + manifest to the individual media segments. This is particularly useful for + maintaining continuity in security, analytics, and any other parameter-based + operations across the entire media delivery workflow. + """ + + redirect_http_to_https: Optional[OptionsRedirectHTTPToHTTPS] + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + redirect_https_to_http: Optional[OptionsRedirectHTTPSToHTTP] + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + referrer_acl: Optional[OptionsReferrerACL] + """Controls access to the CDN resource content for specified domain names.""" + + request_limiter: Optional[OptionsRequestLimiter] + """Option allows to limit the amount of HTTP requests.""" + + response_headers_hiding_policy: Optional[OptionsResponseHeadersHidingPolicy] + """Hides HTTP headers from an origin server in the CDN response.""" + + rewrite: Optional[OptionsRewrite] + """Changes and redirects requests from the CDN to the origin. + + It operates according to the + [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) + configuration. + """ + + secure_key: Optional[OptionsSecureKey] + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + slice: Optional[OptionsSlice] + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per + part.) This reduces time to first byte. + + The option is based on the + [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` + options enabled. + """ + + sni: Optional[OptionsSni] + """ + The hostname that is added to SNI requests from CDN servers to the origin server + via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not + have a dedicated IP address. If the origin server presents multiple + certificates, SNI allows the origin server to know which certificate to use for + the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + stale: Optional[OptionsStale] + """Serves stale cached content in case of origin unavailability.""" + + static_response_headers: Optional[OptionsStaticResponseHeaders] + """Custom HTTP Headers that a CDN server adds to a response.""" + + static_headers: Annotated[Optional[OptionsStaticHeaders], PropertyInfo(alias="staticHeaders")] + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP + Headers can be specified. May contain a header with multiple values. + """ + + static_request_headers: Annotated[Optional[OptionsStaticRequestHeaders], PropertyInfo(alias="staticRequestHeaders")] + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + tls_versions: Optional[OptionsTlsVersions] + """ + List of SSL/TLS protocol versions allowed for HTTPS connections from end users + to the domain. + + When the option is disabled, all protocols versions are allowed. + """ + + use_default_le_chain: Optional[OptionsUseDefaultLeChain] + """Let's Encrypt certificate chain. + + The specified chain will be used during the next Let's Encrypt certificate issue + or renewal. + """ + + use_dns01_le_challenge: Optional[OptionsUseDns01LeChallenge] + """DNS-01 challenge to issue a Let's Encrypt certificate for the resource. + + DNS service should be activated to enable this option. + """ + + use_rsa_le_cert: Optional[OptionsUseRsaLeCert] + """RSA Let's Encrypt certificate type for the CDN resource. + + The specified value will be used during the next Let's Encrypt certificate issue + or renewal. + """ + + user_agent_acl: Optional[OptionsUserAgentACL] + """Controls access to the content for specified User-Agents.""" + + waap: Optional[OptionsWaap] + """Allows to enable WAAP (Web Application and API Protection).""" + + websockets: Optional[OptionsWebsockets] + """Enables or disables WebSockets connections to an origin server.""" diff --git a/src/gcore/types/cdn/cdn_resource_update_params.py b/src/gcore/types/cdn/cdn_resource_update_params.py new file mode 100644 index 00000000..4a907f53 --- /dev/null +++ b/src/gcore/types/cdn/cdn_resource_update_params.py @@ -0,0 +1,2105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable, Optional +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = [ + "CDNResourceUpdateParams", + "Options", + "OptionsAllowedHTTPMethods", + "OptionsBotProtection", + "OptionsBotProtectionBotChallenge", + "OptionsBrotliCompression", + "OptionsBrowserCacheSettings", + "OptionsCacheHTTPHeaders", + "OptionsCors", + "OptionsCountryACL", + "OptionsDisableCache", + "OptionsDisableProxyForceRanges", + "OptionsEdgeCacheSettings", + "OptionsFastedge", + "OptionsFastedgeOnRequestBody", + "OptionsFastedgeOnRequestHeaders", + "OptionsFastedgeOnResponseBody", + "OptionsFastedgeOnResponseHeaders", + "OptionsFetchCompressed", + "OptionsFollowOriginRedirect", + "OptionsForceReturn", + "OptionsForceReturnTimeInterval", + "OptionsForwardHostHeader", + "OptionsGzipOn", + "OptionsHostHeader", + "OptionsHttp3Enabled", + "OptionsIgnoreCookie", + "OptionsIgnoreQueryString", + "OptionsImageStack", + "OptionsIPAddressACL", + "OptionsLimitBandwidth", + "OptionsProxyCacheKey", + "OptionsProxyCacheMethodsSet", + "OptionsProxyConnectTimeout", + "OptionsProxyReadTimeout", + "OptionsQueryParamsBlacklist", + "OptionsQueryParamsWhitelist", + "OptionsQueryStringForwarding", + "OptionsRedirectHTTPToHTTPS", + "OptionsRedirectHTTPSToHTTP", + "OptionsReferrerACL", + "OptionsRequestLimiter", + "OptionsResponseHeadersHidingPolicy", + "OptionsRewrite", + "OptionsSecureKey", + "OptionsSlice", + "OptionsSni", + "OptionsStale", + "OptionsStaticResponseHeaders", + "OptionsStaticResponseHeadersValue", + "OptionsStaticHeaders", + "OptionsStaticRequestHeaders", + "OptionsTlsVersions", + "OptionsUseDefaultLeChain", + "OptionsUseDns01LeChallenge", + "OptionsUseRsaLeCert", + "OptionsUserAgentACL", + "OptionsWaap", + "OptionsWebsockets", +] + + +class CDNResourceUpdateParams(TypedDict, total=False): + active: bool + """Enables or disables a CDN resource. + + Possible values: + + - **true** - CDN resource is active. Content is being delivered. + - **false** - CDN resource is deactivated. Content is not being delivered. + """ + + description: str + """Optional comment describing the CDN resource.""" + + name: Optional[str] + """CDN resource name.""" + + options: Options + """List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. Option may + inherit its value from the global account settings. + """ + + origin_group: Annotated[int, PropertyInfo(alias="originGroup")] + """Origin group ID with which the CDN resource is associated.""" + + origin_protocol: Annotated[Literal["HTTP", "HTTPS", "MATCH"], PropertyInfo(alias="originProtocol")] + """Protocol used by CDN servers to request content from an origin source. + + Possible values: + + - **HTTPS** - CDN servers will connect to the origin via HTTPS. + - **HTTP** - CDN servers will connect to the origin via HTTP. + - **MATCH** - connection protocol will be chosen automatically (content on the + origin source should be available for the CDN both through HTTP and HTTPS). + + If protocol is not specified, HTTP is used to connect to an origin server. + """ + + proxy_ssl_ca: Optional[int] + """ID of the trusted CA certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + """ + + proxy_ssl_data: Optional[int] + """ID of the SSL certificate used to verify an origin. + + It can be used only with `"proxy_ssl_enabled": true`. + """ + + proxy_ssl_enabled: bool + """ + Enables or disables SSL certificate validation of the origin server before + completing any connection. + + Possible values: + + - **true** - Origin SSL certificate validation is enabled. + - **false** - Origin SSL certificate validation is disabled. + """ + + secondary_hostnames: Annotated[SequenceNotStr[str], PropertyInfo(alias="secondaryHostnames")] + """ + Additional delivery domains (CNAMEs) that will be used to deliver content via + the CDN. + + Up to ten additional CNAMEs are possible. + """ + + ssl_data: Annotated[Optional[int], PropertyInfo(alias="sslData")] + """ID of the SSL certificate linked to the CDN resource. + + Can be used only with `"sslEnabled": true`. + """ + + ssl_enabled: Annotated[bool, PropertyInfo(alias="sslEnabled")] + """Defines whether the HTTPS protocol enabled for content delivery. + + Possible values: + + - **true** - HTTPS is enabled. + - **false** - HTTPS is disabled. + """ + + +class OptionsAllowedHTTPMethods(TypedDict, total=False): + """HTTP methods allowed for content requests from the CDN.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[List[Literal["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]]] + + +class OptionsBotProtectionBotChallenge(TypedDict, total=False): + """Controls the bot challenge module state.""" + + enabled: bool + """Possible values: + + - **true** - Bot challenge is enabled. + - **false** - Bot challenge is disabled. + """ + + +class OptionsBotProtection(TypedDict, total=False): + """ + Allows to prevent online services from overloading and ensure your business workflow running smoothly. + """ + + bot_challenge: Required[OptionsBotProtectionBotChallenge] + """Controls the bot challenge module state.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsBrotliCompression(TypedDict, total=False): + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN resource and want to enable `brotli_compression` in a rule, you must specify `fetch_compressed:false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "application/javascript", + "application/json", + "application/vnd.ms-fontobject", + "application/wasm", + "application/x-font-ttf", + "application/x-javascript", + "application/xml", + "application/xml+rss", + "image/svg+xml", + "image/x-icon", + "text/css", + "text/html", + "text/javascript", + "text/plain", + "text/xml", + ] + ] + ] + """Allows to select the content types you want to compress. + + `text/html` is a mandatory content type. + """ + + +class OptionsBrowserCacheSettings(TypedDict, total=False): + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Set the cache expiration time to '0s' to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsCacheHTTPHeaders(TypedDict, total=False): + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + + +class OptionsCors(TypedDict, total=False): + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header to a response to a browser. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """Value of the Access-Control-Allow-Origin header. + + Possible values: + + - **Adds \\** as the Access-Control-Allow-Origin header value** - Content will be + uploaded for requests from any domain. `"value": ["*"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value if the + origin matches one of the listed domains** - Content will be uploaded only for + requests from the domains specified in the field. + `"value": ["domain.com", "second.dom.com"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value** - + Content will be uploaded for requests from any domain, and the domain from + which the request was sent will be added to the "Access-Control-Allow-Origin" + header in the response. `"value": ["$http_origin"]` + """ + + always: bool + """ + Defines whether the Access-Control-Allow-Origin header should be added to a + response from CDN regardless of response code. + + Possible values: + + - **true** - Header will be added to a response regardless of response code. + - **false** - Header will only be added to responses with codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsCountryACL(TypedDict, total=False): + """Enables control access to content for specified countries.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of countries according to ISO-3166-1. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of countries for which access is prohibited. + - **deny** - List of countries for which access is allowed. + """ + + policy_type: Required[Literal["allow", "deny"]] + """Defines the type of CDN resource access policy. + + Possible values: + + - **allow** - Access is allowed for all the countries except for those specified + in `excepted_values` field. + - **deny** - Access is denied for all the countries except for those specified + in `excepted_values` field. + """ + + +class OptionsDisableCache(TypedDict, total=False): + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - content caching is disabled. + - **false** - content caching is enabled. + """ + + +class OptionsDisableProxyForceRanges(TypedDict, total=False): + """Allows 206 responses regardless of the settings of an origin source.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsEdgeCacheSettings(TypedDict, total=False): + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + custom_values: Dict[str, str] + """ + A MAP object representing the caching time in seconds for a response with a + specific response code. + + These settings have a higher priority than the `value` field. + + - Use `any` key to specify caching time for all response codes. + - Use `0s` value to disable caching for a specific response code. + """ + + default: str + """Enables content caching according to the origin cache settings. + + The value is applied to the following response codes 200, 201, 204, 206, 301, + 302, 303, 304, 307, 308, if an origin server does not have caching HTTP headers. + + Responses with other codes will not be cached. + + The maximum duration is any equivalent to `1y`. + """ + + value: str + """Caching time. + + The value is applied to the following response codes: 200, 206, 301, 302. + Responses with codes 4xx, 5xx will not be cached. + + Use `0s` to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsFastedgeOnRequestBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request body as soon as CDN receives incoming HTTP request. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnRequestHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response body before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response headers before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedge(TypedDict, total=False): + """ + Allows to configure FastEdge app to be called on different request/response phases. + + Note: At least one of `on_request_headers`, `on_request_body`, `on_response_headers`, or `on_response_body` must be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + on_request_body: OptionsFastedgeOnRequestBody + """ + Allows to configure FastEdge application that will be called to handle request + body as soon as CDN receives incoming HTTP request. + """ + + on_request_headers: OptionsFastedgeOnRequestHeaders + """ + Allows to configure FastEdge application that will be called to handle request + headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + on_response_body: OptionsFastedgeOnResponseBody + """ + Allows to configure FastEdge application that will be called to handle response + body before CDN sends the HTTP response. + """ + + on_response_headers: OptionsFastedgeOnResponseHeaders + """ + Allows to configure FastEdge application that will be called to handle response + headers before CDN sends the HTTP response. + """ + + +class OptionsFetchCompressed(TypedDict, total=False): + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If you enable it in CDN resource and want to use `gzipON` and `brotli_compression` in a rule, you have to specify `"fetch_compressed": false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsFollowOriginRedirect(TypedDict, total=False): + """ + Enables redirection from origin. + If the origin server returns a redirect, the option allows the CDN to pull the requested content from the origin server that was returned in the redirect. + """ + + codes: Required[Iterable[Literal[301, 302, 303, 307, 308]]] + """Redirect status code that the origin server returns. + + To serve up to date content to end users, you will need to purge the cache after + managing the option. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsForceReturnTimeInterval(TypedDict, total=False): + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + end_time: Required[str] + """Time until which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + start_time: Required[str] + """Time from which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + time_zone: str + """Time zone used to calculate time.""" + + +class OptionsForceReturn(TypedDict, total=False): + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + body: Required[str] + """URL for redirection or text.""" + + code: Required[int] + """Status code value.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + time_interval: Optional[OptionsForceReturnTimeInterval] + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + +class OptionsForwardHostHeader(TypedDict, total=False): + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsGzipOn(TypedDict, total=False): + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in rules. If you enable `fetch_compressed` in CDN resource and want to enable `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsHostHeader(TypedDict, total=False): + """ + Sets the Host header that CDN servers use when request content from an origin server. + Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Host Header value.""" + + +class OptionsHttp3Enabled(TypedDict, total=False): + """Enables HTTP/3 protocol for content delivery. + + `http3_enabled` option works only with `"sslEnabled": true`. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsIgnoreCookie(TypedDict, total=False): + """ + Defines whether the files with the Set-Cookies header are cached as one file or as different ones. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled, files with cookies are cached as one file. + - **false** - Option is disabled, files with cookies are cached as different + files. + """ + + +class OptionsIgnoreQueryString(TypedDict, total=False): + """ + How a file with different query strings is cached: either as one object (option is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsImageStack(TypedDict, total=False): + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically converts them to WebP or AVIF format. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + avif_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to AVI format.""" + + png_lossless: bool + """Enables or disables compression without quality loss for PNG format.""" + + quality: int + """Defines quality settings for JPG and PNG images. + + The higher the value, the better the image quality, and the larger the file size + after conversion. + """ + + webp_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to WebP format.""" + + +class OptionsIPAddressACL(TypedDict, total=False): + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of IP addresses with a subnet mask. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of IP addresses for which access is prohibited. + - **deny** - List of IP addresses for which access is allowed. + + Examples: + + - `192.168.3.2/32` + - `2a03:d000:2980:7::8/128` + """ + + policy_type: Required[Literal["allow", "deny"]] + """IP access policy type. + + Possible values: + + - **allow** - Allow access to all IPs except IPs specified in "excepted_values" + field. + - **deny** - Deny access to all IPs except IPs specified in "excepted_values" + field. + """ + + +class OptionsLimitBandwidth(TypedDict, total=False): + """Allows to control the download speed per connection.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + limit_type: Required[Literal["static", "dynamic"]] + """Method of controlling the download speed per connection. + + Possible values: + + - **static** - Use speed and buffer fields to set the download speed limit. + - **dynamic** - Use query strings **speed** and **buffer** to set the download + speed limit. + + For example, when requesting content at the link + + ``` + http://cdn.example.com/video.mp4?speed=50k&buffer=500k + ``` + + the download speed will be limited to 50kB/s after 500 kB. + """ + + buffer: int + """Amount of downloaded data after which the user will be rate limited.""" + + speed: int + """Maximum download speed per connection.""" + + +class OptionsProxyCacheKey(TypedDict, total=False): + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will not work. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Key for caching.""" + + +class OptionsProxyCacheMethodsSet(TypedDict, total=False): + """Caching for POST requests along with default GET and HEAD.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsProxyConnectTimeout(TypedDict, total=False): + """The time limit for establishing a connection with the origin.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 5s**. + """ + + +class OptionsProxyReadTimeout(TypedDict, total=False): + """ + The time limit for receiving a partial response from the origin. + If no response is received within this time, the connection will be closed. + + **Note:** + When used with a WebSocket connection, this option supports values only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 30s**. + """ + + +class OptionsQueryParamsBlacklist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as one object, files with other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryParamsWhitelist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as different objects, files with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryStringForwarding(TypedDict, total=False): + """ + The Query String Forwarding feature allows for the seamless transfer of parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication tokens or tracking information, are consistently passed along from the playlist manifest to the individual media segments. + This is particularly useful for maintaining continuity in security, analytics, and any other parameter-based operations across the entire media delivery workflow. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + forward_from_file_types: Required[SequenceNotStr[str]] + """ + The `forward_from_files_types` field specifies the types of playlist files from + which parameters will be extracted and forwarded. This typically includes + formats that list multiple media chunk references, such as HLS and DASH + playlists. Parameters associated with these playlist files (like query strings + or headers) will be propagated to the chunks they reference. + """ + + forward_to_file_types: Required[SequenceNotStr[str]] + """ + The field specifies the types of media chunk files to which parameters, + extracted from playlist files, will be forwarded. These refer to the actual + segments of media content that are delivered to viewers. Ensuring the correct + parameters are forwarded to these files is crucial for maintaining the integrity + of the streaming session. + """ + + forward_except_keys: SequenceNotStr[str] + """ + The `forward_except_keys` field provides a mechanism to exclude specific + parameters from being forwarded from playlist files to media chunk files. By + listing certain keys in this field, you can ensure that these parameters are + omitted during the forwarding process. This is particularly useful for + preventing sensitive or irrelevant information from being included in requests + for media chunks, thereby enhancing security and optimizing performance. + """ + + forward_only_keys: SequenceNotStr[str] + """ + The `forward_only_keys` field allows for granular control over which specific + parameters are forwarded from playlist files to media chunk files. By specifying + certain keys, only those parameters will be propagated, ensuring that only + relevant information is passed along. This is particularly useful for security + and performance optimization, as it prevents unnecessary or sensitive data from + being included in requests for media chunks. + """ + + +class OptionsRedirectHTTPToHTTPS(TypedDict, total=False): + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsRedirectHTTPSToHTTP(TypedDict, total=False): + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsReferrerACL(TypedDict, total=False): + """Controls access to the CDN resource content for specified domain names.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """ + List of domain names or wildcard domains (without protocol: `http://` or + `https://`.) + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of domain names for which access is prohibited. + - **deny** - List of IP domain names for which access is allowed. + + Examples: + + - `example.com` + - `*.example.com` + """ + + policy_type: Required[Literal["allow", "deny"]] + """Policy type. + + Possible values: + + - **allow** - Allow access to all domain names except the domain names specified + in `excepted_values` field. + - **deny** - Deny access to all domain names except the domain names specified + in `excepted_values` field. + """ + + +class OptionsRequestLimiter(TypedDict, total=False): + """Option allows to limit the amount of HTTP requests.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + rate: Required[int] + """Maximum request rate.""" + + rate_unit: Literal["r/s", "r/m"] + """Units of measurement for the `rate` field. + + Possible values: + + - **r/s** - Requests per second. + - **r/m** - Requests per minute. + + If the rate is less than one request per second, it is specified in request per + minute (r/m.) + """ + + +class OptionsResponseHeadersHidingPolicy(TypedDict, total=False): + """Hides HTTP headers from an origin server in the CDN response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted: Required[SequenceNotStr[str]] + """List of HTTP headers. + + Parameter meaning depends on the value of the `mode` field: + + - **show** - List of HTTP headers to hide from response. + - **hide** - List of HTTP headers to include in response. Other HTTP headers + will be hidden. + + The following headers are required and cannot be hidden from response: + + - `Connection` + - `Content-Length` + - `Content-Type` + - `Date` + - `Server` + """ + + mode: Required[Literal["hide", "show"]] + """How HTTP headers are hidden from the response. + + Possible values: + + - **show** - Hide only HTTP headers listed in the `excepted` field. + - **hide** - Hide all HTTP headers except headers listed in the "excepted" + field. + """ + + +class OptionsRewrite(TypedDict, total=False): + """Changes and redirects requests from the CDN to the origin. + + It operates according to the [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) configuration. + """ + + body: Required[str] + """Path for the Rewrite option. + + Example: + + - `/(.*) /media/$1` + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + flag: Literal["break", "last", "redirect", "permanent"] + """Flag for the Rewrite option. + + Possible values: + + - **last** - Stop processing the current set of `ngx_http_rewrite_module` + directives and start a search for a new location matching changed URI. + - **break** - Stop processing the current set of the Rewrite option. + - **redirect** - Return a temporary redirect with the 302 code; used when a + replacement string does not start with `http://`, `https://`, or `$scheme`. + - **permanent** - Return a permanent redirect with the 301 code. + """ + + +class OptionsSecureKey(TypedDict, total=False): + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + key: Required[Optional[str]] + """Key generated on your side that will be used for URL signing.""" + + type: Literal[0, 2] + """Type of URL signing. + + Possible types: + + - **Type 0** - Includes end user IP to secure token generation. + - **Type 2** - Excludes end user IP from secure token generation. + """ + + +class OptionsSlice(TypedDict, total=False): + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per part.) This reduces time to first byte. + + The option is based on the [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` options enabled. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsSni(TypedDict, total=False): + """ + The hostname that is added to SNI requests from CDN servers to the origin server via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not have a dedicated IP address. + If the origin server presents multiple certificates, SNI allows the origin server to know which certificate to use for the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + custom_hostname: Required[str] + """Custom SNI hostname. + + It is required if `sni_type` is set to custom. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + sni_type: Literal["dynamic", "custom"] + """SNI (Server Name Indication) type. + + Possible values: + + - **dynamic** - SNI hostname depends on `hostHeader` and `forward_host_header` + options. It has several possible combinations: + - If the `hostHeader` option is enabled and specified, SNI hostname matches the + Host header. + - If the `forward_host_header` option is enabled and has true value, SNI + hostname matches the Host header used in the request made to a CDN. + - If the `hostHeader` and `forward_host_header` options are disabled, SNI + hostname matches the primary CNAME. + - **custom** - custom SNI hostname is in use. + """ + + +class OptionsStale(TypedDict, total=False): + """Serves stale cached content in case of origin unavailability.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "error", + "http_403", + "http_404", + "http_429", + "http_500", + "http_502", + "http_503", + "http_504", + "invalid_header", + "timeout", + "updating", + ] + ] + ] + """Defines list of errors for which "Always online" option is applied.""" + + +class OptionsStaticResponseHeadersValue(TypedDict, total=False): + name: Required[str] + """HTTP Header name. + + Restrictions: + + - Maximum 128 symbols. + - Latin letters (A-Z, a-z,) numbers (0-9,) dashes, and underscores only. + """ + + value: Required[SequenceNotStr[str]] + """Header value. + + Restrictions: + + - Maximum 512 symbols. + - Letters (a-z), numbers (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ + /|\";:?.,><{}[]). + - Must start with a letter, number, asterisk or {. + - Multiple values can be added. + """ + + always: bool + """ + Defines whether the header will be added to a response from CDN regardless of + response code. + + Possible values: + + - **true** - Header will be added to a response from CDN regardless of response + code. + - **false** - Header will be added only to the following response codes: 200, + 201, 204, 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsStaticResponseHeaders(TypedDict, total=False): + """Custom HTTP Headers that a CDN server adds to a response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Iterable[OptionsStaticResponseHeadersValue]] + + +class OptionsStaticHeaders(TypedDict, total=False): + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP Headers can be specified. May contain a header with multiple values. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[object] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 128 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsStaticRequestHeaders(TypedDict, total=False): + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Dict[str, str]] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 255 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsTlsVersions(TypedDict, total=False): + """ + List of SSL/TLS protocol versions allowed for HTTPS connections from end users to the domain. + + When the option is disabled, all protocols versions are allowed. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[List[Literal["SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"]]] + """List of SSL/TLS protocol versions (case sensitive).""" + + +class OptionsUseDefaultLeChain(TypedDict, total=False): + """Let's Encrypt certificate chain. + + The specified chain will be used during the next Let's Encrypt certificate issue or renewal. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Default Let's Encrypt certificate chain. This is a deprecated + version, use it only for compatibilities with Android devices 7.1.1 or lower. + - **false** - Alternative Let's Encrypt certificate chain. + """ + + +class OptionsUseDns01LeChallenge(TypedDict, total=False): + """DNS-01 challenge to issue a Let's Encrypt certificate for the resource. + + DNS service should be activated to enable this option. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - DNS-01 challenge is used to issue Let's Encrypt certificate. + - **false** - HTTP-01 challenge is used to issue Let's Encrypt certificate. + """ + + +class OptionsUseRsaLeCert(TypedDict, total=False): + """RSA Let's Encrypt certificate type for the CDN resource. + + The specified value will be used during the next Let's Encrypt certificate issue or renewal. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - RSA Let's Encrypt certificate. + - **false** - ECDSA Let's Encrypt certificate. + """ + + +class OptionsUserAgentACL(TypedDict, total=False): + """Controls access to the content for specified User-Agents.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of User-Agents that will be allowed/denied. + + The meaning of the parameter depends on `policy_type`: + + - **allow** - List of User-Agents for which access is prohibited. + - **deny** - List of User-Agents for which access is allowed. + + You can provide exact User-Agent strings or regular expressions. Regular + expressions must start with `~` (case-sensitive) or `~*` (case-insensitive). + + Use an empty string `""` to allow/deny access when the User-Agent header is + empty. + """ + + policy_type: Required[Literal["allow", "deny"]] + """User-Agents policy type. + + Possible values: + + - **allow** - Allow access for all User-Agents except specified in + `excepted_values` field. + - **deny** - Deny access for all User-Agents except specified in + `excepted_values` field. + """ + + +class OptionsWaap(TypedDict, total=False): + """Allows to enable WAAP (Web Application and API Protection).""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsWebsockets(TypedDict, total=False): + """Enables or disables WebSockets connections to an origin server.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class Options(TypedDict, total=False): + """List of options that can be configured for the CDN resource. + + In case of `null` value the option is not added to the CDN resource. + Option may inherit its value from the global account settings. + """ + + allowed_http_methods: Annotated[Optional[OptionsAllowedHTTPMethods], PropertyInfo(alias="allowedHttpMethods")] + """HTTP methods allowed for content requests from the CDN.""" + + bot_protection: Optional[OptionsBotProtection] + """ + Allows to prevent online services from overloading and ensure your business + workflow running smoothly. + """ + + brotli_compression: Optional[OptionsBrotliCompression] + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is + activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, + even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` + options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides + `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN + resource and want to enable `brotli_compression` in a rule, you must specify + `fetch_compressed:false` in the rule. + """ + + browser_cache_settings: Optional[OptionsBrowserCacheSettings] + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + cache_http_headers: Optional[OptionsCacheHTTPHeaders] + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + cors: Optional[OptionsCors] + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header + to a response to a browser. + """ + + country_acl: Optional[OptionsCountryACL] + """Enables control access to content for specified countries.""" + + disable_cache: Optional[OptionsDisableCache] + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + disable_proxy_force_ranges: Optional[OptionsDisableProxyForceRanges] + """Allows 206 responses regardless of the settings of an origin source.""" + + edge_cache_settings: Optional[OptionsEdgeCacheSettings] + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + fastedge: Optional[OptionsFastedge] + """ + Allows to configure FastEdge app to be called on different request/response + phases. + + Note: At least one of `on_request_headers`, `on_request_body`, + `on_response_headers`, or `on_response_body` must be specified. + """ + + fetch_compressed: Optional[OptionsFetchCompressed] + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress + your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or + `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If + you enable it in CDN resource and want to use `gzipON` and + `brotli_compression` in a rule, you have to specify + `"fetch_compressed": false` in the rule. + """ + + follow_origin_redirect: Optional[OptionsFollowOriginRedirect] + """ + Enables redirection from origin. If the origin server returns a redirect, the + option allows the CDN to pull the requested content from the origin server that + was returned in the redirect. + """ + + force_return: Optional[OptionsForceReturn] + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this + option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + forward_host_header: Optional[OptionsForwardHostHeader] + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + gzip_on: Annotated[Optional[OptionsGzipOn], PropertyInfo(alias="gzipOn")] + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` + options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in + rules. If you enable `fetch_compressed` in CDN resource and want to enable + `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + host_header: Annotated[Optional[OptionsHostHeader], PropertyInfo(alias="hostHeader")] + """ + Sets the Host header that CDN servers use when request content from an origin + server. Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + http3_enabled: Optional[OptionsHttp3Enabled] + """Enables HTTP/3 protocol for content delivery. + + `http3_enabled` option works only with `"sslEnabled": true`. + """ + + ignore_cookie: Optional[OptionsIgnoreCookie] + """ + Defines whether the files with the Set-Cookies header are cached as one file or + as different ones. + """ + + ignore_query_string: Annotated[Optional[OptionsIgnoreQueryString], PropertyInfo(alias="ignoreQueryString")] + """ + How a file with different query strings is cached: either as one object (option + is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + image_stack: Optional[OptionsImageStack] + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically + converts them to WebP or AVIF format. + """ + + ip_address_acl: Optional[OptionsIPAddressACL] + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, + you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. + [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + limit_bandwidth: Optional[OptionsLimitBandwidth] + """Allows to control the download speed per connection.""" + + proxy_cache_key: Optional[OptionsProxyCacheKey] + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache + and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will + not work. + """ + + proxy_cache_methods_set: Optional[OptionsProxyCacheMethodsSet] + """Caching for POST requests along with default GET and HEAD.""" + + proxy_connect_timeout: Optional[OptionsProxyConnectTimeout] + """The time limit for establishing a connection with the origin.""" + + proxy_read_timeout: Optional[OptionsProxyReadTimeout] + """ + The time limit for receiving a partial response from the origin. If no response + is received within this time, the connection will be closed. + + **Note:** When used with a WebSocket connection, this option supports values + only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + query_params_blacklist: Optional[OptionsQueryParamsBlacklist] + """ + Files with the specified query parameters are cached as one object, files with + other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_params_whitelist: Optional[OptionsQueryParamsWhitelist] + """ + Files with the specified query parameters are cached as different objects, files + with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_string_forwarding: Optional[OptionsQueryStringForwarding] + """ + The Query String Forwarding feature allows for the seamless transfer of + parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication + tokens or tracking information, are consistently passed along from the playlist + manifest to the individual media segments. This is particularly useful for + maintaining continuity in security, analytics, and any other parameter-based + operations across the entire media delivery workflow. + """ + + redirect_http_to_https: Optional[OptionsRedirectHTTPToHTTPS] + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + redirect_https_to_http: Optional[OptionsRedirectHTTPSToHTTP] + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + referrer_acl: Optional[OptionsReferrerACL] + """Controls access to the CDN resource content for specified domain names.""" + + request_limiter: Optional[OptionsRequestLimiter] + """Option allows to limit the amount of HTTP requests.""" + + response_headers_hiding_policy: Optional[OptionsResponseHeadersHidingPolicy] + """Hides HTTP headers from an origin server in the CDN response.""" + + rewrite: Optional[OptionsRewrite] + """Changes and redirects requests from the CDN to the origin. + + It operates according to the + [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) + configuration. + """ + + secure_key: Optional[OptionsSecureKey] + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + slice: Optional[OptionsSlice] + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per + part.) This reduces time to first byte. + + The option is based on the + [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` + options enabled. + """ + + sni: Optional[OptionsSni] + """ + The hostname that is added to SNI requests from CDN servers to the origin server + via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not + have a dedicated IP address. If the origin server presents multiple + certificates, SNI allows the origin server to know which certificate to use for + the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + stale: Optional[OptionsStale] + """Serves stale cached content in case of origin unavailability.""" + + static_response_headers: Optional[OptionsStaticResponseHeaders] + """Custom HTTP Headers that a CDN server adds to a response.""" + + static_headers: Annotated[Optional[OptionsStaticHeaders], PropertyInfo(alias="staticHeaders")] + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP + Headers can be specified. May contain a header with multiple values. + """ + + static_request_headers: Annotated[Optional[OptionsStaticRequestHeaders], PropertyInfo(alias="staticRequestHeaders")] + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + tls_versions: Optional[OptionsTlsVersions] + """ + List of SSL/TLS protocol versions allowed for HTTPS connections from end users + to the domain. + + When the option is disabled, all protocols versions are allowed. + """ + + use_default_le_chain: Optional[OptionsUseDefaultLeChain] + """Let's Encrypt certificate chain. + + The specified chain will be used during the next Let's Encrypt certificate issue + or renewal. + """ + + use_dns01_le_challenge: Optional[OptionsUseDns01LeChallenge] + """DNS-01 challenge to issue a Let's Encrypt certificate for the resource. + + DNS service should be activated to enable this option. + """ + + use_rsa_le_cert: Optional[OptionsUseRsaLeCert] + """RSA Let's Encrypt certificate type for the CDN resource. + + The specified value will be used during the next Let's Encrypt certificate issue + or renewal. + """ + + user_agent_acl: Optional[OptionsUserAgentACL] + """Controls access to the content for specified User-Agents.""" + + waap: Optional[OptionsWaap] + """Allows to enable WAAP (Web Application and API Protection).""" + + websockets: Optional[OptionsWebsockets] + """Enables or disables WebSockets connections to an origin server.""" diff --git a/src/gcore/types/cdn/cdn_resources/__init__.py b/src/gcore/types/cdn/cdn_resources/__init__.py new file mode 100644 index 00000000..b004f9f1 --- /dev/null +++ b/src/gcore/types/cdn/cdn_resources/__init__.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .origin_shielding import OriginShielding as OriginShielding +from .cdn_resource_rule import CDNResourceRule as CDNResourceRule +from .rule_create_params import RuleCreateParams as RuleCreateParams +from .rule_list_response import RuleListResponse as RuleListResponse +from .rule_update_params import RuleUpdateParams as RuleUpdateParams +from .rule_replace_params import RuleReplaceParams as RuleReplaceParams +from .shield_replace_params import ShieldReplaceParams as ShieldReplaceParams diff --git a/src/gcore/types/cdn/cdn_resources/cdn_resource_rule.py b/src/gcore/types/cdn/cdn_resources/cdn_resource_rule.py new file mode 100644 index 00000000..6c3b02bf --- /dev/null +++ b/src/gcore/types/cdn/cdn_resources/cdn_resource_rule.py @@ -0,0 +1,1983 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel + +__all__ = [ + "CDNResourceRule", + "Options", + "OptionsAllowedHTTPMethods", + "OptionsBotProtection", + "OptionsBotProtectionBotChallenge", + "OptionsBrotliCompression", + "OptionsBrowserCacheSettings", + "OptionsCacheHTTPHeaders", + "OptionsCors", + "OptionsCountryACL", + "OptionsDisableCache", + "OptionsDisableProxyForceRanges", + "OptionsEdgeCacheSettings", + "OptionsFastedge", + "OptionsFastedgeOnRequestBody", + "OptionsFastedgeOnRequestHeaders", + "OptionsFastedgeOnResponseBody", + "OptionsFastedgeOnResponseHeaders", + "OptionsFetchCompressed", + "OptionsFollowOriginRedirect", + "OptionsForceReturn", + "OptionsForceReturnTimeInterval", + "OptionsForwardHostHeader", + "OptionsGzipOn", + "OptionsHostHeader", + "OptionsIgnoreCookie", + "OptionsIgnoreQueryString", + "OptionsImageStack", + "OptionsIPAddressACL", + "OptionsLimitBandwidth", + "OptionsProxyCacheKey", + "OptionsProxyCacheMethodsSet", + "OptionsProxyConnectTimeout", + "OptionsProxyReadTimeout", + "OptionsQueryParamsBlacklist", + "OptionsQueryParamsWhitelist", + "OptionsQueryStringForwarding", + "OptionsRedirectHTTPToHTTPS", + "OptionsRedirectHTTPSToHTTP", + "OptionsReferrerACL", + "OptionsRequestLimiter", + "OptionsResponseHeadersHidingPolicy", + "OptionsRewrite", + "OptionsSecureKey", + "OptionsSlice", + "OptionsSni", + "OptionsStale", + "OptionsStaticResponseHeaders", + "OptionsStaticResponseHeadersValue", + "OptionsStaticHeaders", + "OptionsStaticRequestHeaders", + "OptionsUserAgentACL", + "OptionsWaap", + "OptionsWebsockets", +] + + +class OptionsAllowedHTTPMethods(BaseModel): + """HTTP methods allowed for content requests from the CDN.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[Literal["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]] + + +class OptionsBotProtectionBotChallenge(BaseModel): + """Controls the bot challenge module state.""" + + enabled: Optional[bool] = None + """Possible values: + + - **true** - Bot challenge is enabled. + - **false** - Bot challenge is disabled. + """ + + +class OptionsBotProtection(BaseModel): + """ + Allows to prevent online services from overloading and ensure your business workflow running smoothly. + """ + + bot_challenge: OptionsBotProtectionBotChallenge + """Controls the bot challenge module state.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsBrotliCompression(BaseModel): + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN resource and want to enable `brotli_compression` in a rule, you must specify `fetch_compressed:false` in the rule. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[ + Literal[ + "application/javascript", + "application/json", + "application/vnd.ms-fontobject", + "application/wasm", + "application/x-font-ttf", + "application/x-javascript", + "application/xml", + "application/xml+rss", + "image/svg+xml", + "image/x-icon", + "text/css", + "text/html", + "text/javascript", + "text/plain", + "text/xml", + ] + ] + """Allows to select the content types you want to compress. + + `text/html` is a mandatory content type. + """ + + +class OptionsBrowserCacheSettings(BaseModel): + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Set the cache expiration time to '0s' to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsCacheHTTPHeaders(BaseModel): + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[str] + + +class OptionsCors(BaseModel): + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header to a response to a browser. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[str] + """Value of the Access-Control-Allow-Origin header. + + Possible values: + + - **Adds \\** as the Access-Control-Allow-Origin header value** - Content will be + uploaded for requests from any domain. `"value": ["*"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value if the + origin matches one of the listed domains** - Content will be uploaded only for + requests from the domains specified in the field. + `"value": ["domain.com", "second.dom.com"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value** - + Content will be uploaded for requests from any domain, and the domain from + which the request was sent will be added to the "Access-Control-Allow-Origin" + header in the response. `"value": ["$http_origin"]` + """ + + always: Optional[bool] = None + """ + Defines whether the Access-Control-Allow-Origin header should be added to a + response from CDN regardless of response code. + + Possible values: + + - **true** - Header will be added to a response regardless of response code. + - **false** - Header will only be added to responses with codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsCountryACL(BaseModel): + """Enables control access to content for specified countries.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: List[str] + """List of countries according to ISO-3166-1. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of countries for which access is prohibited. + - **deny** - List of countries for which access is allowed. + """ + + policy_type: Literal["allow", "deny"] + """Defines the type of CDN resource access policy. + + Possible values: + + - **allow** - Access is allowed for all the countries except for those specified + in `excepted_values` field. + - **deny** - Access is denied for all the countries except for those specified + in `excepted_values` field. + """ + + +class OptionsDisableCache(BaseModel): + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - content caching is disabled. + - **false** - content caching is enabled. + """ + + +class OptionsDisableProxyForceRanges(BaseModel): + """Allows 206 responses regardless of the settings of an origin source.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsEdgeCacheSettings(BaseModel): + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + custom_values: Optional[Dict[str, str]] = None + """ + A MAP object representing the caching time in seconds for a response with a + specific response code. + + These settings have a higher priority than the `value` field. + + - Use `any` key to specify caching time for all response codes. + - Use `0s` value to disable caching for a specific response code. + """ + + default: Optional[str] = None + """Enables content caching according to the origin cache settings. + + The value is applied to the following response codes 200, 201, 204, 206, 301, + 302, 303, 304, 307, 308, if an origin server does not have caching HTTP headers. + + Responses with other codes will not be cached. + + The maximum duration is any equivalent to `1y`. + """ + + value: Optional[str] = None + """Caching time. + + The value is applied to the following response codes: 200, 206, 301, 302. + Responses with codes 4xx, 5xx will not be cached. + + Use `0s` to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsFastedgeOnRequestBody(BaseModel): + """ + Allows to configure FastEdge application that will be called to handle request body as soon as CDN receives incoming HTTP request. + """ + + app_id: str + """The ID of the application in FastEdge.""" + + enabled: Optional[bool] = None + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: Optional[bool] = None + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: Optional[bool] = None + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: Optional[bool] = None + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnRequestHeaders(BaseModel): + """ + Allows to configure FastEdge application that will be called to handle request headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + app_id: str + """The ID of the application in FastEdge.""" + + enabled: Optional[bool] = None + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: Optional[bool] = None + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: Optional[bool] = None + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: Optional[bool] = None + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseBody(BaseModel): + """ + Allows to configure FastEdge application that will be called to handle response body before CDN sends the HTTP response. + """ + + app_id: str + """The ID of the application in FastEdge.""" + + enabled: Optional[bool] = None + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: Optional[bool] = None + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: Optional[bool] = None + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: Optional[bool] = None + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseHeaders(BaseModel): + """ + Allows to configure FastEdge application that will be called to handle response headers before CDN sends the HTTP response. + """ + + app_id: str + """The ID of the application in FastEdge.""" + + enabled: Optional[bool] = None + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: Optional[bool] = None + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: Optional[bool] = None + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: Optional[bool] = None + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedge(BaseModel): + """ + Allows to configure FastEdge app to be called on different request/response phases. + + Note: At least one of `on_request_headers`, `on_request_body`, `on_response_headers`, or `on_response_body` must be specified. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + on_request_body: Optional[OptionsFastedgeOnRequestBody] = None + """ + Allows to configure FastEdge application that will be called to handle request + body as soon as CDN receives incoming HTTP request. + """ + + on_request_headers: Optional[OptionsFastedgeOnRequestHeaders] = None + """ + Allows to configure FastEdge application that will be called to handle request + headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + on_response_body: Optional[OptionsFastedgeOnResponseBody] = None + """ + Allows to configure FastEdge application that will be called to handle response + body before CDN sends the HTTP response. + """ + + on_response_headers: Optional[OptionsFastedgeOnResponseHeaders] = None + """ + Allows to configure FastEdge application that will be called to handle response + headers before CDN sends the HTTP response. + """ + + +class OptionsFetchCompressed(BaseModel): + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If you enable it in CDN resource and want to use `gzipON` and `brotli_compression` in a rule, you have to specify `"fetch_compressed": false` in the rule. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsFollowOriginRedirect(BaseModel): + """ + Enables redirection from origin. + If the origin server returns a redirect, the option allows the CDN to pull the requested content from the origin server that was returned in the redirect. + """ + + codes: List[Literal[301, 302, 303, 307, 308]] + """Redirect status code that the origin server returns. + + To serve up to date content to end users, you will need to purge the cache after + managing the option. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsForceReturnTimeInterval(BaseModel): + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + end_time: str + """Time until which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + start_time: str + """Time from which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + time_zone: Optional[str] = None + """Time zone used to calculate time.""" + + +class OptionsForceReturn(BaseModel): + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + body: str + """URL for redirection or text.""" + + code: int + """Status code value.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + time_interval: Optional[OptionsForceReturnTimeInterval] = None + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + +class OptionsForwardHostHeader(BaseModel): + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsGzipOn(BaseModel): + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in rules. If you enable `fetch_compressed` in CDN resource and want to enable `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsHostHeader(BaseModel): + """ + Sets the Host header that CDN servers use when request content from an origin server. + Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Host Header value.""" + + +class OptionsIgnoreCookie(BaseModel): + """ + Defines whether the files with the Set-Cookies header are cached as one file or as different ones. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled, files with cookies are cached as one file. + - **false** - Option is disabled, files with cookies are cached as different + files. + """ + + +class OptionsIgnoreQueryString(BaseModel): + """ + How a file with different query strings is cached: either as one object (option is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsImageStack(BaseModel): + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically converts them to WebP or AVIF format. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + avif_enabled: Optional[bool] = None + """Enables or disables automatic conversion of JPEG and PNG images to AVI format.""" + + png_lossless: Optional[bool] = None + """Enables or disables compression without quality loss for PNG format.""" + + quality: Optional[int] = None + """Defines quality settings for JPG and PNG images. + + The higher the value, the better the image quality, and the larger the file size + after conversion. + """ + + webp_enabled: Optional[bool] = None + """Enables or disables automatic conversion of JPEG and PNG images to WebP format.""" + + +class OptionsIPAddressACL(BaseModel): + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: List[str] + """List of IP addresses with a subnet mask. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of IP addresses for which access is prohibited. + - **deny** - List of IP addresses for which access is allowed. + + Examples: + + - `192.168.3.2/32` + - `2a03:d000:2980:7::8/128` + """ + + policy_type: Literal["allow", "deny"] + """IP access policy type. + + Possible values: + + - **allow** - Allow access to all IPs except IPs specified in "excepted_values" + field. + - **deny** - Deny access to all IPs except IPs specified in "excepted_values" + field. + """ + + +class OptionsLimitBandwidth(BaseModel): + """Allows to control the download speed per connection.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + limit_type: Literal["static", "dynamic"] + """Method of controlling the download speed per connection. + + Possible values: + + - **static** - Use speed and buffer fields to set the download speed limit. + - **dynamic** - Use query strings **speed** and **buffer** to set the download + speed limit. + + For example, when requesting content at the link + + ``` + http://cdn.example.com/video.mp4?speed=50k&buffer=500k + ``` + + the download speed will be limited to 50kB/s after 500 kB. + """ + + buffer: Optional[int] = None + """Amount of downloaded data after which the user will be rate limited.""" + + speed: Optional[int] = None + """Maximum download speed per connection.""" + + +class OptionsProxyCacheKey(BaseModel): + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will not work. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Key for caching.""" + + +class OptionsProxyCacheMethodsSet(BaseModel): + """Caching for POST requests along with default GET and HEAD.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsProxyConnectTimeout(BaseModel): + """The time limit for establishing a connection with the origin.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Timeout value in seconds. + + Supported range: **1s - 5s**. + """ + + +class OptionsProxyReadTimeout(BaseModel): + """ + The time limit for receiving a partial response from the origin. + If no response is received within this time, the connection will be closed. + + **Note:** + When used with a WebSocket connection, this option supports values only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Timeout value in seconds. + + Supported range: **1s - 30s**. + """ + + +class OptionsQueryParamsBlacklist(BaseModel): + """ + Files with the specified query parameters are cached as one object, files with other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[str] + """List of query parameters.""" + + +class OptionsQueryParamsWhitelist(BaseModel): + """ + Files with the specified query parameters are cached as different objects, files with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[str] + """List of query parameters.""" + + +class OptionsQueryStringForwarding(BaseModel): + """ + The Query String Forwarding feature allows for the seamless transfer of parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication tokens or tracking information, are consistently passed along from the playlist manifest to the individual media segments. + This is particularly useful for maintaining continuity in security, analytics, and any other parameter-based operations across the entire media delivery workflow. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + forward_from_file_types: List[str] + """ + The `forward_from_files_types` field specifies the types of playlist files from + which parameters will be extracted and forwarded. This typically includes + formats that list multiple media chunk references, such as HLS and DASH + playlists. Parameters associated with these playlist files (like query strings + or headers) will be propagated to the chunks they reference. + """ + + forward_to_file_types: List[str] + """ + The field specifies the types of media chunk files to which parameters, + extracted from playlist files, will be forwarded. These refer to the actual + segments of media content that are delivered to viewers. Ensuring the correct + parameters are forwarded to these files is crucial for maintaining the integrity + of the streaming session. + """ + + forward_except_keys: Optional[List[str]] = None + """ + The `forward_except_keys` field provides a mechanism to exclude specific + parameters from being forwarded from playlist files to media chunk files. By + listing certain keys in this field, you can ensure that these parameters are + omitted during the forwarding process. This is particularly useful for + preventing sensitive or irrelevant information from being included in requests + for media chunks, thereby enhancing security and optimizing performance. + """ + + forward_only_keys: Optional[List[str]] = None + """ + The `forward_only_keys` field allows for granular control over which specific + parameters are forwarded from playlist files to media chunk files. By specifying + certain keys, only those parameters will be propagated, ensuring that only + relevant information is passed along. This is particularly useful for security + and performance optimization, as it prevents unnecessary or sensitive data from + being included in requests for media chunks. + """ + + +class OptionsRedirectHTTPToHTTPS(BaseModel): + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsRedirectHTTPSToHTTP(BaseModel): + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsReferrerACL(BaseModel): + """Controls access to the CDN resource content for specified domain names.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: List[str] + """ + List of domain names or wildcard domains (without protocol: `http://` or + `https://`.) + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of domain names for which access is prohibited. + - **deny** - List of IP domain names for which access is allowed. + + Examples: + + - `example.com` + - `*.example.com` + """ + + policy_type: Literal["allow", "deny"] + """Policy type. + + Possible values: + + - **allow** - Allow access to all domain names except the domain names specified + in `excepted_values` field. + - **deny** - Deny access to all domain names except the domain names specified + in `excepted_values` field. + """ + + +class OptionsRequestLimiter(BaseModel): + """Option allows to limit the amount of HTTP requests.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + rate: int + """Maximum request rate.""" + + burst: Optional[int] = None + + delay: Optional[int] = None + + rate_unit: Optional[Literal["r/s", "r/m"]] = None + """Units of measurement for the `rate` field. + + Possible values: + + - **r/s** - Requests per second. + - **r/m** - Requests per minute. + + If the rate is less than one request per second, it is specified in request per + minute (r/m.) + """ + + +class OptionsResponseHeadersHidingPolicy(BaseModel): + """Hides HTTP headers from an origin server in the CDN response.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted: List[str] + """List of HTTP headers. + + Parameter meaning depends on the value of the `mode` field: + + - **show** - List of HTTP headers to hide from response. + - **hide** - List of HTTP headers to include in response. Other HTTP headers + will be hidden. + + The following headers are required and cannot be hidden from response: + + - `Connection` + - `Content-Length` + - `Content-Type` + - `Date` + - `Server` + """ + + mode: Literal["hide", "show"] + """How HTTP headers are hidden from the response. + + Possible values: + + - **show** - Hide only HTTP headers listed in the `excepted` field. + - **hide** - Hide all HTTP headers except headers listed in the "excepted" + field. + """ + + +class OptionsRewrite(BaseModel): + """Changes and redirects requests from the CDN to the origin. + + It operates according to the [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) configuration. + """ + + body: str + """Path for the Rewrite option. + + Example: + + - `/(.*) /media/$1` + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + flag: Optional[Literal["break", "last", "redirect", "permanent"]] = None + """Flag for the Rewrite option. + + Possible values: + + - **last** - Stop processing the current set of `ngx_http_rewrite_module` + directives and start a search for a new location matching changed URI. + - **break** - Stop processing the current set of the Rewrite option. + - **redirect** - Return a temporary redirect with the 302 code; used when a + replacement string does not start with `http://`, `https://`, or `$scheme`. + - **permanent** - Return a permanent redirect with the 301 code. + """ + + +class OptionsSecureKey(BaseModel): + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + key: Optional[str] = None + """Key generated on your side that will be used for URL signing.""" + + type: Optional[Literal[0, 2]] = None + """Type of URL signing. + + Possible types: + + - **Type 0** - Includes end user IP to secure token generation. + - **Type 2** - Excludes end user IP from secure token generation. + """ + + +class OptionsSlice(BaseModel): + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per part.) This reduces time to first byte. + + The option is based on the [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` options enabled. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsSni(BaseModel): + """ + The hostname that is added to SNI requests from CDN servers to the origin server via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not have a dedicated IP address. + If the origin server presents multiple certificates, SNI allows the origin server to know which certificate to use for the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + custom_hostname: str + """Custom SNI hostname. + + It is required if `sni_type` is set to custom. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + sni_type: Optional[Literal["dynamic", "custom"]] = None + """SNI (Server Name Indication) type. + + Possible values: + + - **dynamic** - SNI hostname depends on `hostHeader` and `forward_host_header` + options. It has several possible combinations: + - If the `hostHeader` option is enabled and specified, SNI hostname matches the + Host header. + - If the `forward_host_header` option is enabled and has true value, SNI + hostname matches the Host header used in the request made to a CDN. + - If the `hostHeader` and `forward_host_header` options are disabled, SNI + hostname matches the primary CNAME. + - **custom** - custom SNI hostname is in use. + """ + + +class OptionsStale(BaseModel): + """Serves stale cached content in case of origin unavailability.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[ + Literal[ + "error", + "http_403", + "http_404", + "http_429", + "http_500", + "http_502", + "http_503", + "http_504", + "invalid_header", + "timeout", + "updating", + ] + ] + """Defines list of errors for which "Always online" option is applied.""" + + +class OptionsStaticResponseHeadersValue(BaseModel): + name: str + """HTTP Header name. + + Restrictions: + + - Maximum 128 symbols. + - Latin letters (A-Z, a-z,) numbers (0-9,) dashes, and underscores only. + """ + + value: List[str] + """Header value. + + Restrictions: + + - Maximum 512 symbols. + - Letters (a-z), numbers (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ + /|\";:?.,><{}[]). + - Must start with a letter, number, asterisk or {. + - Multiple values can be added. + """ + + always: Optional[bool] = None + """ + Defines whether the header will be added to a response from CDN regardless of + response code. + + Possible values: + + - **true** - Header will be added to a response from CDN regardless of response + code. + - **false** - Header will be added only to the following response codes: 200, + 201, 204, 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsStaticResponseHeaders(BaseModel): + """Custom HTTP Headers that a CDN server adds to a response.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[OptionsStaticResponseHeadersValue] + + +class OptionsStaticHeaders(BaseModel): + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP Headers can be specified. May contain a header with multiple values. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: object + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 128 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsStaticRequestHeaders(BaseModel): + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Dict[str, str] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 255 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsUserAgentACL(BaseModel): + """Controls access to the content for specified User-Agents.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: List[str] + """List of User-Agents that will be allowed/denied. + + The meaning of the parameter depends on `policy_type`: + + - **allow** - List of User-Agents for which access is prohibited. + - **deny** - List of User-Agents for which access is allowed. + + You can provide exact User-Agent strings or regular expressions. Regular + expressions must start with `~` (case-sensitive) or `~*` (case-insensitive). + + Use an empty string `""` to allow/deny access when the User-Agent header is + empty. + """ + + policy_type: Literal["allow", "deny"] + """User-Agents policy type. + + Possible values: + + - **allow** - Allow access for all User-Agents except specified in + `excepted_values` field. + - **deny** - Deny access for all User-Agents except specified in + `excepted_values` field. + """ + + +class OptionsWaap(BaseModel): + """Allows to enable WAAP (Web Application and API Protection).""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsWebsockets(BaseModel): + """Enables or disables WebSockets connections to an origin server.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class Options(BaseModel): + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. + Option inherits its value from the CDN resource settings. + """ + + allowed_http_methods: Optional[OptionsAllowedHTTPMethods] = FieldInfo(alias="allowedHttpMethods", default=None) + """HTTP methods allowed for content requests from the CDN.""" + + bot_protection: Optional[OptionsBotProtection] = None + """ + Allows to prevent online services from overloading and ensure your business + workflow running smoothly. + """ + + brotli_compression: Optional[OptionsBrotliCompression] = None + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is + activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, + even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` + options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides + `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN + resource and want to enable `brotli_compression` in a rule, you must specify + `fetch_compressed:false` in the rule. + """ + + browser_cache_settings: Optional[OptionsBrowserCacheSettings] = None + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + cache_http_headers: Optional[OptionsCacheHTTPHeaders] = None + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + cors: Optional[OptionsCors] = None + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header + to a response to a browser. + """ + + country_acl: Optional[OptionsCountryACL] = None + """Enables control access to content for specified countries.""" + + disable_cache: Optional[OptionsDisableCache] = None + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + disable_proxy_force_ranges: Optional[OptionsDisableProxyForceRanges] = None + """Allows 206 responses regardless of the settings of an origin source.""" + + edge_cache_settings: Optional[OptionsEdgeCacheSettings] = None + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + fastedge: Optional[OptionsFastedge] = None + """ + Allows to configure FastEdge app to be called on different request/response + phases. + + Note: At least one of `on_request_headers`, `on_request_body`, + `on_response_headers`, or `on_response_body` must be specified. + """ + + fetch_compressed: Optional[OptionsFetchCompressed] = None + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress + your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or + `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If + you enable it in CDN resource and want to use `gzipON` and + `brotli_compression` in a rule, you have to specify + `"fetch_compressed": false` in the rule. + """ + + follow_origin_redirect: Optional[OptionsFollowOriginRedirect] = None + """ + Enables redirection from origin. If the origin server returns a redirect, the + option allows the CDN to pull the requested content from the origin server that + was returned in the redirect. + """ + + force_return: Optional[OptionsForceReturn] = None + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this + option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + forward_host_header: Optional[OptionsForwardHostHeader] = None + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + gzip_on: Optional[OptionsGzipOn] = FieldInfo(alias="gzipOn", default=None) + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` + options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in + rules. If you enable `fetch_compressed` in CDN resource and want to enable + `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + host_header: Optional[OptionsHostHeader] = FieldInfo(alias="hostHeader", default=None) + """ + Sets the Host header that CDN servers use when request content from an origin + server. Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + ignore_cookie: Optional[OptionsIgnoreCookie] = None + """ + Defines whether the files with the Set-Cookies header are cached as one file or + as different ones. + """ + + ignore_query_string: Optional[OptionsIgnoreQueryString] = FieldInfo(alias="ignoreQueryString", default=None) + """ + How a file with different query strings is cached: either as one object (option + is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + image_stack: Optional[OptionsImageStack] = None + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically + converts them to WebP or AVIF format. + """ + + ip_address_acl: Optional[OptionsIPAddressACL] = None + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, + you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. + [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + limit_bandwidth: Optional[OptionsLimitBandwidth] = None + """Allows to control the download speed per connection.""" + + proxy_cache_key: Optional[OptionsProxyCacheKey] = None + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache + and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will + not work. + """ + + proxy_cache_methods_set: Optional[OptionsProxyCacheMethodsSet] = None + """Caching for POST requests along with default GET and HEAD.""" + + proxy_connect_timeout: Optional[OptionsProxyConnectTimeout] = None + """The time limit for establishing a connection with the origin.""" + + proxy_read_timeout: Optional[OptionsProxyReadTimeout] = None + """ + The time limit for receiving a partial response from the origin. If no response + is received within this time, the connection will be closed. + + **Note:** When used with a WebSocket connection, this option supports values + only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + query_params_blacklist: Optional[OptionsQueryParamsBlacklist] = None + """ + Files with the specified query parameters are cached as one object, files with + other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_params_whitelist: Optional[OptionsQueryParamsWhitelist] = None + """ + Files with the specified query parameters are cached as different objects, files + with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_string_forwarding: Optional[OptionsQueryStringForwarding] = None + """ + The Query String Forwarding feature allows for the seamless transfer of + parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication + tokens or tracking information, are consistently passed along from the playlist + manifest to the individual media segments. This is particularly useful for + maintaining continuity in security, analytics, and any other parameter-based + operations across the entire media delivery workflow. + """ + + redirect_http_to_https: Optional[OptionsRedirectHTTPToHTTPS] = None + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + redirect_https_to_http: Optional[OptionsRedirectHTTPSToHTTP] = None + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + referrer_acl: Optional[OptionsReferrerACL] = None + """Controls access to the CDN resource content for specified domain names.""" + + request_limiter: Optional[OptionsRequestLimiter] = None + """Option allows to limit the amount of HTTP requests.""" + + response_headers_hiding_policy: Optional[OptionsResponseHeadersHidingPolicy] = None + """Hides HTTP headers from an origin server in the CDN response.""" + + rewrite: Optional[OptionsRewrite] = None + """Changes and redirects requests from the CDN to the origin. + + It operates according to the + [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) + configuration. + """ + + secure_key: Optional[OptionsSecureKey] = None + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + slice: Optional[OptionsSlice] = None + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per + part.) This reduces time to first byte. + + The option is based on the + [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` + options enabled. + """ + + sni: Optional[OptionsSni] = None + """ + The hostname that is added to SNI requests from CDN servers to the origin server + via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not + have a dedicated IP address. If the origin server presents multiple + certificates, SNI allows the origin server to know which certificate to use for + the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + stale: Optional[OptionsStale] = None + """Serves stale cached content in case of origin unavailability.""" + + static_response_headers: Optional[OptionsStaticResponseHeaders] = None + """Custom HTTP Headers that a CDN server adds to a response.""" + + static_headers: Optional[OptionsStaticHeaders] = FieldInfo(alias="staticHeaders", default=None) + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP + Headers can be specified. May contain a header with multiple values. + """ + + static_request_headers: Optional[OptionsStaticRequestHeaders] = FieldInfo( + alias="staticRequestHeaders", default=None + ) + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + user_agent_acl: Optional[OptionsUserAgentACL] = None + """Controls access to the content for specified User-Agents.""" + + waap: Optional[OptionsWaap] = None + """Allows to enable WAAP (Web Application and API Protection).""" + + websockets: Optional[OptionsWebsockets] = None + """Enables or disables WebSockets connections to an origin server.""" + + +class CDNResourceRule(BaseModel): + id: Optional[int] = None + """Rule ID.""" + + active: Optional[bool] = None + """Enables or disables a rule. + + Possible values: + + - **true** - Rule is active, rule settings are applied. + - **false** - Rule is inactive, rule settings are not applied. + """ + + deleted: Optional[bool] = None + """Defines whether the rule has been deleted. + + Possible values: + + - **true** - Rule has been deleted. + - **false** - Rule has not been deleted. + """ + + name: Optional[str] = None + """Rule name.""" + + options: Optional[Options] = None + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + """ + + origin_group: Optional[int] = FieldInfo(alias="originGroup", default=None) + """ID of the origin group to which the rule is applied. + + If the origin group is not specified, the rule is applied to the origin group + that the CDN resource is associated with. + """ + + origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] = FieldInfo(alias="originProtocol", default=None) + """Protocol used by CDN servers to request content from an origin source. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + """ + + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] = FieldInfo( + alias="overrideOriginProtocol", default=None + ) + """ + Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + """ + + preset_applied: Optional[bool] = None + """Defines whether the rule has an applied preset. + + Possible values: + + - **true** - Rule has a preset applied. + - **false** - Rule does not have a preset applied. + + If a preset is applied to the rule, the options included in the preset cannot be + edited for the rule. + """ + + primary_rule: Optional[int] = None + """ + ID of the rule with which the current rule is synchronized within the CDN + resource shared cache zone feature. + """ + + rule: Optional[str] = None + """Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + """ + + rule_type: Optional[int] = FieldInfo(alias="ruleType", default=None) + """Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + """ + + weight: Optional[int] = None + """Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + """ diff --git a/src/gcore/types/cdn/cdn_resources/origin_shielding.py b/src/gcore/types/cdn/cdn_resources/origin_shielding.py new file mode 100644 index 00000000..f188e7ac --- /dev/null +++ b/src/gcore/types/cdn/cdn_resources/origin_shielding.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["OriginShielding"] + + +class OriginShielding(BaseModel): + shielding_pop: Optional[int] = None + """Shielding location ID. + + If origin shielding is disabled, the parameter value is **null**. + """ diff --git a/src/gcore/types/cdn/cdn_resources/rule_create_params.py b/src/gcore/types/cdn/cdn_resources/rule_create_params.py new file mode 100644 index 00000000..0426cd93 --- /dev/null +++ b/src/gcore/types/cdn/cdn_resources/rule_create_params.py @@ -0,0 +1,1940 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable, Optional +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ...._types import SequenceNotStr +from ...._utils import PropertyInfo + +__all__ = [ + "RuleCreateParams", + "Options", + "OptionsAllowedHTTPMethods", + "OptionsBotProtection", + "OptionsBotProtectionBotChallenge", + "OptionsBrotliCompression", + "OptionsBrowserCacheSettings", + "OptionsCacheHTTPHeaders", + "OptionsCors", + "OptionsCountryACL", + "OptionsDisableCache", + "OptionsDisableProxyForceRanges", + "OptionsEdgeCacheSettings", + "OptionsFastedge", + "OptionsFastedgeOnRequestBody", + "OptionsFastedgeOnRequestHeaders", + "OptionsFastedgeOnResponseBody", + "OptionsFastedgeOnResponseHeaders", + "OptionsFetchCompressed", + "OptionsFollowOriginRedirect", + "OptionsForceReturn", + "OptionsForceReturnTimeInterval", + "OptionsForwardHostHeader", + "OptionsGzipOn", + "OptionsHostHeader", + "OptionsIgnoreCookie", + "OptionsIgnoreQueryString", + "OptionsImageStack", + "OptionsIPAddressACL", + "OptionsLimitBandwidth", + "OptionsProxyCacheKey", + "OptionsProxyCacheMethodsSet", + "OptionsProxyConnectTimeout", + "OptionsProxyReadTimeout", + "OptionsQueryParamsBlacklist", + "OptionsQueryParamsWhitelist", + "OptionsQueryStringForwarding", + "OptionsRedirectHTTPToHTTPS", + "OptionsRedirectHTTPSToHTTP", + "OptionsReferrerACL", + "OptionsRequestLimiter", + "OptionsResponseHeadersHidingPolicy", + "OptionsRewrite", + "OptionsSecureKey", + "OptionsSlice", + "OptionsSni", + "OptionsStale", + "OptionsStaticResponseHeaders", + "OptionsStaticResponseHeadersValue", + "OptionsStaticHeaders", + "OptionsStaticRequestHeaders", + "OptionsUserAgentACL", + "OptionsWaap", + "OptionsWebsockets", +] + + +class RuleCreateParams(TypedDict, total=False): + name: Required[str] + """Rule name.""" + + rule: Required[str] + """Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + """ + + rule_type: Required[Annotated[int, PropertyInfo(alias="ruleType")]] + """Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + """ + + active: bool + """Enables or disables a rule. + + Possible values: + + - **true** - Rule is active, rule settings are applied. + - **false** - Rule is inactive, rule settings are not applied. + """ + + options: Options + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + """ + + origin_group: Annotated[Optional[int], PropertyInfo(alias="originGroup")] + """ID of the origin group to which the rule is applied. + + If the origin group is not specified, the rule is applied to the origin group + that the CDN resource is associated with. + """ + + override_origin_protocol: Annotated[ + Optional[Literal["HTTPS", "HTTP", "MATCH"]], PropertyInfo(alias="overrideOriginProtocol") + ] + """ + Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + """ + + weight: int + """Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + """ + + +class OptionsAllowedHTTPMethods(TypedDict, total=False): + """HTTP methods allowed for content requests from the CDN.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[List[Literal["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]]] + + +class OptionsBotProtectionBotChallenge(TypedDict, total=False): + """Controls the bot challenge module state.""" + + enabled: bool + """Possible values: + + - **true** - Bot challenge is enabled. + - **false** - Bot challenge is disabled. + """ + + +class OptionsBotProtection(TypedDict, total=False): + """ + Allows to prevent online services from overloading and ensure your business workflow running smoothly. + """ + + bot_challenge: Required[OptionsBotProtectionBotChallenge] + """Controls the bot challenge module state.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsBrotliCompression(TypedDict, total=False): + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN resource and want to enable `brotli_compression` in a rule, you must specify `fetch_compressed:false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "application/javascript", + "application/json", + "application/vnd.ms-fontobject", + "application/wasm", + "application/x-font-ttf", + "application/x-javascript", + "application/xml", + "application/xml+rss", + "image/svg+xml", + "image/x-icon", + "text/css", + "text/html", + "text/javascript", + "text/plain", + "text/xml", + ] + ] + ] + """Allows to select the content types you want to compress. + + `text/html` is a mandatory content type. + """ + + +class OptionsBrowserCacheSettings(TypedDict, total=False): + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Set the cache expiration time to '0s' to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsCacheHTTPHeaders(TypedDict, total=False): + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + + +class OptionsCors(TypedDict, total=False): + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header to a response to a browser. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """Value of the Access-Control-Allow-Origin header. + + Possible values: + + - **Adds \\** as the Access-Control-Allow-Origin header value** - Content will be + uploaded for requests from any domain. `"value": ["*"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value if the + origin matches one of the listed domains** - Content will be uploaded only for + requests from the domains specified in the field. + `"value": ["domain.com", "second.dom.com"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value** - + Content will be uploaded for requests from any domain, and the domain from + which the request was sent will be added to the "Access-Control-Allow-Origin" + header in the response. `"value": ["$http_origin"]` + """ + + always: bool + """ + Defines whether the Access-Control-Allow-Origin header should be added to a + response from CDN regardless of response code. + + Possible values: + + - **true** - Header will be added to a response regardless of response code. + - **false** - Header will only be added to responses with codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsCountryACL(TypedDict, total=False): + """Enables control access to content for specified countries.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of countries according to ISO-3166-1. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of countries for which access is prohibited. + - **deny** - List of countries for which access is allowed. + """ + + policy_type: Required[Literal["allow", "deny"]] + """Defines the type of CDN resource access policy. + + Possible values: + + - **allow** - Access is allowed for all the countries except for those specified + in `excepted_values` field. + - **deny** - Access is denied for all the countries except for those specified + in `excepted_values` field. + """ + + +class OptionsDisableCache(TypedDict, total=False): + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - content caching is disabled. + - **false** - content caching is enabled. + """ + + +class OptionsDisableProxyForceRanges(TypedDict, total=False): + """Allows 206 responses regardless of the settings of an origin source.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsEdgeCacheSettings(TypedDict, total=False): + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + custom_values: Dict[str, str] + """ + A MAP object representing the caching time in seconds for a response with a + specific response code. + + These settings have a higher priority than the `value` field. + + - Use `any` key to specify caching time for all response codes. + - Use `0s` value to disable caching for a specific response code. + """ + + default: str + """Enables content caching according to the origin cache settings. + + The value is applied to the following response codes 200, 201, 204, 206, 301, + 302, 303, 304, 307, 308, if an origin server does not have caching HTTP headers. + + Responses with other codes will not be cached. + + The maximum duration is any equivalent to `1y`. + """ + + value: str + """Caching time. + + The value is applied to the following response codes: 200, 206, 301, 302. + Responses with codes 4xx, 5xx will not be cached. + + Use `0s` to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsFastedgeOnRequestBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request body as soon as CDN receives incoming HTTP request. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnRequestHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response body before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response headers before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedge(TypedDict, total=False): + """ + Allows to configure FastEdge app to be called on different request/response phases. + + Note: At least one of `on_request_headers`, `on_request_body`, `on_response_headers`, or `on_response_body` must be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + on_request_body: OptionsFastedgeOnRequestBody + """ + Allows to configure FastEdge application that will be called to handle request + body as soon as CDN receives incoming HTTP request. + """ + + on_request_headers: OptionsFastedgeOnRequestHeaders + """ + Allows to configure FastEdge application that will be called to handle request + headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + on_response_body: OptionsFastedgeOnResponseBody + """ + Allows to configure FastEdge application that will be called to handle response + body before CDN sends the HTTP response. + """ + + on_response_headers: OptionsFastedgeOnResponseHeaders + """ + Allows to configure FastEdge application that will be called to handle response + headers before CDN sends the HTTP response. + """ + + +class OptionsFetchCompressed(TypedDict, total=False): + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If you enable it in CDN resource and want to use `gzipON` and `brotli_compression` in a rule, you have to specify `"fetch_compressed": false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsFollowOriginRedirect(TypedDict, total=False): + """ + Enables redirection from origin. + If the origin server returns a redirect, the option allows the CDN to pull the requested content from the origin server that was returned in the redirect. + """ + + codes: Required[Iterable[Literal[301, 302, 303, 307, 308]]] + """Redirect status code that the origin server returns. + + To serve up to date content to end users, you will need to purge the cache after + managing the option. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsForceReturnTimeInterval(TypedDict, total=False): + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + end_time: Required[str] + """Time until which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + start_time: Required[str] + """Time from which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + time_zone: str + """Time zone used to calculate time.""" + + +class OptionsForceReturn(TypedDict, total=False): + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + body: Required[str] + """URL for redirection or text.""" + + code: Required[int] + """Status code value.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + time_interval: Optional[OptionsForceReturnTimeInterval] + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + +class OptionsForwardHostHeader(TypedDict, total=False): + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsGzipOn(TypedDict, total=False): + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in rules. If you enable `fetch_compressed` in CDN resource and want to enable `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsHostHeader(TypedDict, total=False): + """ + Sets the Host header that CDN servers use when request content from an origin server. + Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Host Header value.""" + + +class OptionsIgnoreCookie(TypedDict, total=False): + """ + Defines whether the files with the Set-Cookies header are cached as one file or as different ones. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled, files with cookies are cached as one file. + - **false** - Option is disabled, files with cookies are cached as different + files. + """ + + +class OptionsIgnoreQueryString(TypedDict, total=False): + """ + How a file with different query strings is cached: either as one object (option is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsImageStack(TypedDict, total=False): + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically converts them to WebP or AVIF format. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + avif_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to AVI format.""" + + png_lossless: bool + """Enables or disables compression without quality loss for PNG format.""" + + quality: int + """Defines quality settings for JPG and PNG images. + + The higher the value, the better the image quality, and the larger the file size + after conversion. + """ + + webp_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to WebP format.""" + + +class OptionsIPAddressACL(TypedDict, total=False): + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of IP addresses with a subnet mask. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of IP addresses for which access is prohibited. + - **deny** - List of IP addresses for which access is allowed. + + Examples: + + - `192.168.3.2/32` + - `2a03:d000:2980:7::8/128` + """ + + policy_type: Required[Literal["allow", "deny"]] + """IP access policy type. + + Possible values: + + - **allow** - Allow access to all IPs except IPs specified in "excepted_values" + field. + - **deny** - Deny access to all IPs except IPs specified in "excepted_values" + field. + """ + + +class OptionsLimitBandwidth(TypedDict, total=False): + """Allows to control the download speed per connection.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + limit_type: Required[Literal["static", "dynamic"]] + """Method of controlling the download speed per connection. + + Possible values: + + - **static** - Use speed and buffer fields to set the download speed limit. + - **dynamic** - Use query strings **speed** and **buffer** to set the download + speed limit. + + For example, when requesting content at the link + + ``` + http://cdn.example.com/video.mp4?speed=50k&buffer=500k + ``` + + the download speed will be limited to 50kB/s after 500 kB. + """ + + buffer: int + """Amount of downloaded data after which the user will be rate limited.""" + + speed: int + """Maximum download speed per connection.""" + + +class OptionsProxyCacheKey(TypedDict, total=False): + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will not work. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Key for caching.""" + + +class OptionsProxyCacheMethodsSet(TypedDict, total=False): + """Caching for POST requests along with default GET and HEAD.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsProxyConnectTimeout(TypedDict, total=False): + """The time limit for establishing a connection with the origin.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 5s**. + """ + + +class OptionsProxyReadTimeout(TypedDict, total=False): + """ + The time limit for receiving a partial response from the origin. + If no response is received within this time, the connection will be closed. + + **Note:** + When used with a WebSocket connection, this option supports values only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 30s**. + """ + + +class OptionsQueryParamsBlacklist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as one object, files with other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryParamsWhitelist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as different objects, files with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryStringForwarding(TypedDict, total=False): + """ + The Query String Forwarding feature allows for the seamless transfer of parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication tokens or tracking information, are consistently passed along from the playlist manifest to the individual media segments. + This is particularly useful for maintaining continuity in security, analytics, and any other parameter-based operations across the entire media delivery workflow. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + forward_from_file_types: Required[SequenceNotStr[str]] + """ + The `forward_from_files_types` field specifies the types of playlist files from + which parameters will be extracted and forwarded. This typically includes + formats that list multiple media chunk references, such as HLS and DASH + playlists. Parameters associated with these playlist files (like query strings + or headers) will be propagated to the chunks they reference. + """ + + forward_to_file_types: Required[SequenceNotStr[str]] + """ + The field specifies the types of media chunk files to which parameters, + extracted from playlist files, will be forwarded. These refer to the actual + segments of media content that are delivered to viewers. Ensuring the correct + parameters are forwarded to these files is crucial for maintaining the integrity + of the streaming session. + """ + + forward_except_keys: SequenceNotStr[str] + """ + The `forward_except_keys` field provides a mechanism to exclude specific + parameters from being forwarded from playlist files to media chunk files. By + listing certain keys in this field, you can ensure that these parameters are + omitted during the forwarding process. This is particularly useful for + preventing sensitive or irrelevant information from being included in requests + for media chunks, thereby enhancing security and optimizing performance. + """ + + forward_only_keys: SequenceNotStr[str] + """ + The `forward_only_keys` field allows for granular control over which specific + parameters are forwarded from playlist files to media chunk files. By specifying + certain keys, only those parameters will be propagated, ensuring that only + relevant information is passed along. This is particularly useful for security + and performance optimization, as it prevents unnecessary or sensitive data from + being included in requests for media chunks. + """ + + +class OptionsRedirectHTTPToHTTPS(TypedDict, total=False): + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsRedirectHTTPSToHTTP(TypedDict, total=False): + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsReferrerACL(TypedDict, total=False): + """Controls access to the CDN resource content for specified domain names.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """ + List of domain names or wildcard domains (without protocol: `http://` or + `https://`.) + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of domain names for which access is prohibited. + - **deny** - List of IP domain names for which access is allowed. + + Examples: + + - `example.com` + - `*.example.com` + """ + + policy_type: Required[Literal["allow", "deny"]] + """Policy type. + + Possible values: + + - **allow** - Allow access to all domain names except the domain names specified + in `excepted_values` field. + - **deny** - Deny access to all domain names except the domain names specified + in `excepted_values` field. + """ + + +class OptionsRequestLimiter(TypedDict, total=False): + """Option allows to limit the amount of HTTP requests.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + rate: Required[int] + """Maximum request rate.""" + + rate_unit: Literal["r/s", "r/m"] + """Units of measurement for the `rate` field. + + Possible values: + + - **r/s** - Requests per second. + - **r/m** - Requests per minute. + + If the rate is less than one request per second, it is specified in request per + minute (r/m.) + """ + + +class OptionsResponseHeadersHidingPolicy(TypedDict, total=False): + """Hides HTTP headers from an origin server in the CDN response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted: Required[SequenceNotStr[str]] + """List of HTTP headers. + + Parameter meaning depends on the value of the `mode` field: + + - **show** - List of HTTP headers to hide from response. + - **hide** - List of HTTP headers to include in response. Other HTTP headers + will be hidden. + + The following headers are required and cannot be hidden from response: + + - `Connection` + - `Content-Length` + - `Content-Type` + - `Date` + - `Server` + """ + + mode: Required[Literal["hide", "show"]] + """How HTTP headers are hidden from the response. + + Possible values: + + - **show** - Hide only HTTP headers listed in the `excepted` field. + - **hide** - Hide all HTTP headers except headers listed in the "excepted" + field. + """ + + +class OptionsRewrite(TypedDict, total=False): + """Changes and redirects requests from the CDN to the origin. + + It operates according to the [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) configuration. + """ + + body: Required[str] + """Path for the Rewrite option. + + Example: + + - `/(.*) /media/$1` + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + flag: Literal["break", "last", "redirect", "permanent"] + """Flag for the Rewrite option. + + Possible values: + + - **last** - Stop processing the current set of `ngx_http_rewrite_module` + directives and start a search for a new location matching changed URI. + - **break** - Stop processing the current set of the Rewrite option. + - **redirect** - Return a temporary redirect with the 302 code; used when a + replacement string does not start with `http://`, `https://`, or `$scheme`. + - **permanent** - Return a permanent redirect with the 301 code. + """ + + +class OptionsSecureKey(TypedDict, total=False): + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + key: Required[Optional[str]] + """Key generated on your side that will be used for URL signing.""" + + type: Literal[0, 2] + """Type of URL signing. + + Possible types: + + - **Type 0** - Includes end user IP to secure token generation. + - **Type 2** - Excludes end user IP from secure token generation. + """ + + +class OptionsSlice(TypedDict, total=False): + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per part.) This reduces time to first byte. + + The option is based on the [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` options enabled. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsSni(TypedDict, total=False): + """ + The hostname that is added to SNI requests from CDN servers to the origin server via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not have a dedicated IP address. + If the origin server presents multiple certificates, SNI allows the origin server to know which certificate to use for the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + custom_hostname: Required[str] + """Custom SNI hostname. + + It is required if `sni_type` is set to custom. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + sni_type: Literal["dynamic", "custom"] + """SNI (Server Name Indication) type. + + Possible values: + + - **dynamic** - SNI hostname depends on `hostHeader` and `forward_host_header` + options. It has several possible combinations: + - If the `hostHeader` option is enabled and specified, SNI hostname matches the + Host header. + - If the `forward_host_header` option is enabled and has true value, SNI + hostname matches the Host header used in the request made to a CDN. + - If the `hostHeader` and `forward_host_header` options are disabled, SNI + hostname matches the primary CNAME. + - **custom** - custom SNI hostname is in use. + """ + + +class OptionsStale(TypedDict, total=False): + """Serves stale cached content in case of origin unavailability.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "error", + "http_403", + "http_404", + "http_429", + "http_500", + "http_502", + "http_503", + "http_504", + "invalid_header", + "timeout", + "updating", + ] + ] + ] + """Defines list of errors for which "Always online" option is applied.""" + + +class OptionsStaticResponseHeadersValue(TypedDict, total=False): + name: Required[str] + """HTTP Header name. + + Restrictions: + + - Maximum 128 symbols. + - Latin letters (A-Z, a-z,) numbers (0-9,) dashes, and underscores only. + """ + + value: Required[SequenceNotStr[str]] + """Header value. + + Restrictions: + + - Maximum 512 symbols. + - Letters (a-z), numbers (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ + /|\";:?.,><{}[]). + - Must start with a letter, number, asterisk or {. + - Multiple values can be added. + """ + + always: bool + """ + Defines whether the header will be added to a response from CDN regardless of + response code. + + Possible values: + + - **true** - Header will be added to a response from CDN regardless of response + code. + - **false** - Header will be added only to the following response codes: 200, + 201, 204, 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsStaticResponseHeaders(TypedDict, total=False): + """Custom HTTP Headers that a CDN server adds to a response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Iterable[OptionsStaticResponseHeadersValue]] + + +class OptionsStaticHeaders(TypedDict, total=False): + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP Headers can be specified. May contain a header with multiple values. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[object] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 128 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsStaticRequestHeaders(TypedDict, total=False): + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Dict[str, str]] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 255 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsUserAgentACL(TypedDict, total=False): + """Controls access to the content for specified User-Agents.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of User-Agents that will be allowed/denied. + + The meaning of the parameter depends on `policy_type`: + + - **allow** - List of User-Agents for which access is prohibited. + - **deny** - List of User-Agents for which access is allowed. + + You can provide exact User-Agent strings or regular expressions. Regular + expressions must start with `~` (case-sensitive) or `~*` (case-insensitive). + + Use an empty string `""` to allow/deny access when the User-Agent header is + empty. + """ + + policy_type: Required[Literal["allow", "deny"]] + """User-Agents policy type. + + Possible values: + + - **allow** - Allow access for all User-Agents except specified in + `excepted_values` field. + - **deny** - Deny access for all User-Agents except specified in + `excepted_values` field. + """ + + +class OptionsWaap(TypedDict, total=False): + """Allows to enable WAAP (Web Application and API Protection).""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsWebsockets(TypedDict, total=False): + """Enables or disables WebSockets connections to an origin server.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class Options(TypedDict, total=False): + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. + Option inherits its value from the CDN resource settings. + """ + + allowed_http_methods: Annotated[Optional[OptionsAllowedHTTPMethods], PropertyInfo(alias="allowedHttpMethods")] + """HTTP methods allowed for content requests from the CDN.""" + + bot_protection: Optional[OptionsBotProtection] + """ + Allows to prevent online services from overloading and ensure your business + workflow running smoothly. + """ + + brotli_compression: Optional[OptionsBrotliCompression] + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is + activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, + even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` + options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides + `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN + resource and want to enable `brotli_compression` in a rule, you must specify + `fetch_compressed:false` in the rule. + """ + + browser_cache_settings: Optional[OptionsBrowserCacheSettings] + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + cache_http_headers: Optional[OptionsCacheHTTPHeaders] + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + cors: Optional[OptionsCors] + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header + to a response to a browser. + """ + + country_acl: Optional[OptionsCountryACL] + """Enables control access to content for specified countries.""" + + disable_cache: Optional[OptionsDisableCache] + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + disable_proxy_force_ranges: Optional[OptionsDisableProxyForceRanges] + """Allows 206 responses regardless of the settings of an origin source.""" + + edge_cache_settings: Optional[OptionsEdgeCacheSettings] + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + fastedge: Optional[OptionsFastedge] + """ + Allows to configure FastEdge app to be called on different request/response + phases. + + Note: At least one of `on_request_headers`, `on_request_body`, + `on_response_headers`, or `on_response_body` must be specified. + """ + + fetch_compressed: Optional[OptionsFetchCompressed] + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress + your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or + `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If + you enable it in CDN resource and want to use `gzipON` and + `brotli_compression` in a rule, you have to specify + `"fetch_compressed": false` in the rule. + """ + + follow_origin_redirect: Optional[OptionsFollowOriginRedirect] + """ + Enables redirection from origin. If the origin server returns a redirect, the + option allows the CDN to pull the requested content from the origin server that + was returned in the redirect. + """ + + force_return: Optional[OptionsForceReturn] + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this + option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + forward_host_header: Optional[OptionsForwardHostHeader] + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + gzip_on: Annotated[Optional[OptionsGzipOn], PropertyInfo(alias="gzipOn")] + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` + options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in + rules. If you enable `fetch_compressed` in CDN resource and want to enable + `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + host_header: Annotated[Optional[OptionsHostHeader], PropertyInfo(alias="hostHeader")] + """ + Sets the Host header that CDN servers use when request content from an origin + server. Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + ignore_cookie: Optional[OptionsIgnoreCookie] + """ + Defines whether the files with the Set-Cookies header are cached as one file or + as different ones. + """ + + ignore_query_string: Annotated[Optional[OptionsIgnoreQueryString], PropertyInfo(alias="ignoreQueryString")] + """ + How a file with different query strings is cached: either as one object (option + is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + image_stack: Optional[OptionsImageStack] + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically + converts them to WebP or AVIF format. + """ + + ip_address_acl: Optional[OptionsIPAddressACL] + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, + you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. + [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + limit_bandwidth: Optional[OptionsLimitBandwidth] + """Allows to control the download speed per connection.""" + + proxy_cache_key: Optional[OptionsProxyCacheKey] + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache + and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will + not work. + """ + + proxy_cache_methods_set: Optional[OptionsProxyCacheMethodsSet] + """Caching for POST requests along with default GET and HEAD.""" + + proxy_connect_timeout: Optional[OptionsProxyConnectTimeout] + """The time limit for establishing a connection with the origin.""" + + proxy_read_timeout: Optional[OptionsProxyReadTimeout] + """ + The time limit for receiving a partial response from the origin. If no response + is received within this time, the connection will be closed. + + **Note:** When used with a WebSocket connection, this option supports values + only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + query_params_blacklist: Optional[OptionsQueryParamsBlacklist] + """ + Files with the specified query parameters are cached as one object, files with + other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_params_whitelist: Optional[OptionsQueryParamsWhitelist] + """ + Files with the specified query parameters are cached as different objects, files + with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_string_forwarding: Optional[OptionsQueryStringForwarding] + """ + The Query String Forwarding feature allows for the seamless transfer of + parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication + tokens or tracking information, are consistently passed along from the playlist + manifest to the individual media segments. This is particularly useful for + maintaining continuity in security, analytics, and any other parameter-based + operations across the entire media delivery workflow. + """ + + redirect_http_to_https: Optional[OptionsRedirectHTTPToHTTPS] + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + redirect_https_to_http: Optional[OptionsRedirectHTTPSToHTTP] + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + referrer_acl: Optional[OptionsReferrerACL] + """Controls access to the CDN resource content for specified domain names.""" + + request_limiter: Optional[OptionsRequestLimiter] + """Option allows to limit the amount of HTTP requests.""" + + response_headers_hiding_policy: Optional[OptionsResponseHeadersHidingPolicy] + """Hides HTTP headers from an origin server in the CDN response.""" + + rewrite: Optional[OptionsRewrite] + """Changes and redirects requests from the CDN to the origin. + + It operates according to the + [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) + configuration. + """ + + secure_key: Optional[OptionsSecureKey] + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + slice: Optional[OptionsSlice] + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per + part.) This reduces time to first byte. + + The option is based on the + [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` + options enabled. + """ + + sni: Optional[OptionsSni] + """ + The hostname that is added to SNI requests from CDN servers to the origin server + via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not + have a dedicated IP address. If the origin server presents multiple + certificates, SNI allows the origin server to know which certificate to use for + the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + stale: Optional[OptionsStale] + """Serves stale cached content in case of origin unavailability.""" + + static_response_headers: Optional[OptionsStaticResponseHeaders] + """Custom HTTP Headers that a CDN server adds to a response.""" + + static_headers: Annotated[Optional[OptionsStaticHeaders], PropertyInfo(alias="staticHeaders")] + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP + Headers can be specified. May contain a header with multiple values. + """ + + static_request_headers: Annotated[Optional[OptionsStaticRequestHeaders], PropertyInfo(alias="staticRequestHeaders")] + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + user_agent_acl: Optional[OptionsUserAgentACL] + """Controls access to the content for specified User-Agents.""" + + waap: Optional[OptionsWaap] + """Allows to enable WAAP (Web Application and API Protection).""" + + websockets: Optional[OptionsWebsockets] + """Enables or disables WebSockets connections to an origin server.""" diff --git a/src/gcore/types/cdn/cdn_resources/rule_list_response.py b/src/gcore/types/cdn/cdn_resources/rule_list_response.py new file mode 100644 index 00000000..333d426a --- /dev/null +++ b/src/gcore/types/cdn/cdn_resources/rule_list_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .cdn_resource_rule import CDNResourceRule + +__all__ = ["RuleListResponse"] + +RuleListResponse: TypeAlias = List[CDNResourceRule] diff --git a/src/gcore/types/cdn/cdn_resources/rule_replace_params.py b/src/gcore/types/cdn/cdn_resources/rule_replace_params.py new file mode 100644 index 00000000..4cbdefaf --- /dev/null +++ b/src/gcore/types/cdn/cdn_resources/rule_replace_params.py @@ -0,0 +1,1942 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable, Optional +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ...._types import SequenceNotStr +from ...._utils import PropertyInfo + +__all__ = [ + "RuleReplaceParams", + "Options", + "OptionsAllowedHTTPMethods", + "OptionsBotProtection", + "OptionsBotProtectionBotChallenge", + "OptionsBrotliCompression", + "OptionsBrowserCacheSettings", + "OptionsCacheHTTPHeaders", + "OptionsCors", + "OptionsCountryACL", + "OptionsDisableCache", + "OptionsDisableProxyForceRanges", + "OptionsEdgeCacheSettings", + "OptionsFastedge", + "OptionsFastedgeOnRequestBody", + "OptionsFastedgeOnRequestHeaders", + "OptionsFastedgeOnResponseBody", + "OptionsFastedgeOnResponseHeaders", + "OptionsFetchCompressed", + "OptionsFollowOriginRedirect", + "OptionsForceReturn", + "OptionsForceReturnTimeInterval", + "OptionsForwardHostHeader", + "OptionsGzipOn", + "OptionsHostHeader", + "OptionsIgnoreCookie", + "OptionsIgnoreQueryString", + "OptionsImageStack", + "OptionsIPAddressACL", + "OptionsLimitBandwidth", + "OptionsProxyCacheKey", + "OptionsProxyCacheMethodsSet", + "OptionsProxyConnectTimeout", + "OptionsProxyReadTimeout", + "OptionsQueryParamsBlacklist", + "OptionsQueryParamsWhitelist", + "OptionsQueryStringForwarding", + "OptionsRedirectHTTPToHTTPS", + "OptionsRedirectHTTPSToHTTP", + "OptionsReferrerACL", + "OptionsRequestLimiter", + "OptionsResponseHeadersHidingPolicy", + "OptionsRewrite", + "OptionsSecureKey", + "OptionsSlice", + "OptionsSni", + "OptionsStale", + "OptionsStaticResponseHeaders", + "OptionsStaticResponseHeadersValue", + "OptionsStaticHeaders", + "OptionsStaticRequestHeaders", + "OptionsUserAgentACL", + "OptionsWaap", + "OptionsWebsockets", +] + + +class RuleReplaceParams(TypedDict, total=False): + resource_id: Required[int] + + rule: Required[str] + """Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + """ + + rule_type: Required[Annotated[int, PropertyInfo(alias="ruleType")]] + """Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + """ + + active: bool + """Enables or disables a rule. + + Possible values: + + - **true** - Rule is active, rule settings are applied. + - **false** - Rule is inactive, rule settings are not applied. + """ + + name: str + """Rule name.""" + + options: Options + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + """ + + origin_group: Annotated[Optional[int], PropertyInfo(alias="originGroup")] + """ID of the origin group to which the rule is applied. + + If the origin group is not specified, the rule is applied to the origin group + that the CDN resource is associated with. + """ + + override_origin_protocol: Annotated[ + Optional[Literal["HTTPS", "HTTP", "MATCH"]], PropertyInfo(alias="overrideOriginProtocol") + ] + """ + Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + """ + + weight: int + """Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + """ + + +class OptionsAllowedHTTPMethods(TypedDict, total=False): + """HTTP methods allowed for content requests from the CDN.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[List[Literal["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]]] + + +class OptionsBotProtectionBotChallenge(TypedDict, total=False): + """Controls the bot challenge module state.""" + + enabled: bool + """Possible values: + + - **true** - Bot challenge is enabled. + - **false** - Bot challenge is disabled. + """ + + +class OptionsBotProtection(TypedDict, total=False): + """ + Allows to prevent online services from overloading and ensure your business workflow running smoothly. + """ + + bot_challenge: Required[OptionsBotProtectionBotChallenge] + """Controls the bot challenge module state.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsBrotliCompression(TypedDict, total=False): + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN resource and want to enable `brotli_compression` in a rule, you must specify `fetch_compressed:false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "application/javascript", + "application/json", + "application/vnd.ms-fontobject", + "application/wasm", + "application/x-font-ttf", + "application/x-javascript", + "application/xml", + "application/xml+rss", + "image/svg+xml", + "image/x-icon", + "text/css", + "text/html", + "text/javascript", + "text/plain", + "text/xml", + ] + ] + ] + """Allows to select the content types you want to compress. + + `text/html` is a mandatory content type. + """ + + +class OptionsBrowserCacheSettings(TypedDict, total=False): + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Set the cache expiration time to '0s' to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsCacheHTTPHeaders(TypedDict, total=False): + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + + +class OptionsCors(TypedDict, total=False): + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header to a response to a browser. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """Value of the Access-Control-Allow-Origin header. + + Possible values: + + - **Adds \\** as the Access-Control-Allow-Origin header value** - Content will be + uploaded for requests from any domain. `"value": ["*"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value if the + origin matches one of the listed domains** - Content will be uploaded only for + requests from the domains specified in the field. + `"value": ["domain.com", "second.dom.com"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value** - + Content will be uploaded for requests from any domain, and the domain from + which the request was sent will be added to the "Access-Control-Allow-Origin" + header in the response. `"value": ["$http_origin"]` + """ + + always: bool + """ + Defines whether the Access-Control-Allow-Origin header should be added to a + response from CDN regardless of response code. + + Possible values: + + - **true** - Header will be added to a response regardless of response code. + - **false** - Header will only be added to responses with codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsCountryACL(TypedDict, total=False): + """Enables control access to content for specified countries.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of countries according to ISO-3166-1. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of countries for which access is prohibited. + - **deny** - List of countries for which access is allowed. + """ + + policy_type: Required[Literal["allow", "deny"]] + """Defines the type of CDN resource access policy. + + Possible values: + + - **allow** - Access is allowed for all the countries except for those specified + in `excepted_values` field. + - **deny** - Access is denied for all the countries except for those specified + in `excepted_values` field. + """ + + +class OptionsDisableCache(TypedDict, total=False): + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - content caching is disabled. + - **false** - content caching is enabled. + """ + + +class OptionsDisableProxyForceRanges(TypedDict, total=False): + """Allows 206 responses regardless of the settings of an origin source.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsEdgeCacheSettings(TypedDict, total=False): + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + custom_values: Dict[str, str] + """ + A MAP object representing the caching time in seconds for a response with a + specific response code. + + These settings have a higher priority than the `value` field. + + - Use `any` key to specify caching time for all response codes. + - Use `0s` value to disable caching for a specific response code. + """ + + default: str + """Enables content caching according to the origin cache settings. + + The value is applied to the following response codes 200, 201, 204, 206, 301, + 302, 303, 304, 307, 308, if an origin server does not have caching HTTP headers. + + Responses with other codes will not be cached. + + The maximum duration is any equivalent to `1y`. + """ + + value: str + """Caching time. + + The value is applied to the following response codes: 200, 206, 301, 302. + Responses with codes 4xx, 5xx will not be cached. + + Use `0s` to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsFastedgeOnRequestBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request body as soon as CDN receives incoming HTTP request. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnRequestHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response body before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response headers before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedge(TypedDict, total=False): + """ + Allows to configure FastEdge app to be called on different request/response phases. + + Note: At least one of `on_request_headers`, `on_request_body`, `on_response_headers`, or `on_response_body` must be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + on_request_body: OptionsFastedgeOnRequestBody + """ + Allows to configure FastEdge application that will be called to handle request + body as soon as CDN receives incoming HTTP request. + """ + + on_request_headers: OptionsFastedgeOnRequestHeaders + """ + Allows to configure FastEdge application that will be called to handle request + headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + on_response_body: OptionsFastedgeOnResponseBody + """ + Allows to configure FastEdge application that will be called to handle response + body before CDN sends the HTTP response. + """ + + on_response_headers: OptionsFastedgeOnResponseHeaders + """ + Allows to configure FastEdge application that will be called to handle response + headers before CDN sends the HTTP response. + """ + + +class OptionsFetchCompressed(TypedDict, total=False): + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If you enable it in CDN resource and want to use `gzipON` and `brotli_compression` in a rule, you have to specify `"fetch_compressed": false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsFollowOriginRedirect(TypedDict, total=False): + """ + Enables redirection from origin. + If the origin server returns a redirect, the option allows the CDN to pull the requested content from the origin server that was returned in the redirect. + """ + + codes: Required[Iterable[Literal[301, 302, 303, 307, 308]]] + """Redirect status code that the origin server returns. + + To serve up to date content to end users, you will need to purge the cache after + managing the option. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsForceReturnTimeInterval(TypedDict, total=False): + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + end_time: Required[str] + """Time until which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + start_time: Required[str] + """Time from which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + time_zone: str + """Time zone used to calculate time.""" + + +class OptionsForceReturn(TypedDict, total=False): + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + body: Required[str] + """URL for redirection or text.""" + + code: Required[int] + """Status code value.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + time_interval: Optional[OptionsForceReturnTimeInterval] + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + +class OptionsForwardHostHeader(TypedDict, total=False): + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsGzipOn(TypedDict, total=False): + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in rules. If you enable `fetch_compressed` in CDN resource and want to enable `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsHostHeader(TypedDict, total=False): + """ + Sets the Host header that CDN servers use when request content from an origin server. + Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Host Header value.""" + + +class OptionsIgnoreCookie(TypedDict, total=False): + """ + Defines whether the files with the Set-Cookies header are cached as one file or as different ones. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled, files with cookies are cached as one file. + - **false** - Option is disabled, files with cookies are cached as different + files. + """ + + +class OptionsIgnoreQueryString(TypedDict, total=False): + """ + How a file with different query strings is cached: either as one object (option is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsImageStack(TypedDict, total=False): + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically converts them to WebP or AVIF format. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + avif_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to AVI format.""" + + png_lossless: bool + """Enables or disables compression without quality loss for PNG format.""" + + quality: int + """Defines quality settings for JPG and PNG images. + + The higher the value, the better the image quality, and the larger the file size + after conversion. + """ + + webp_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to WebP format.""" + + +class OptionsIPAddressACL(TypedDict, total=False): + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of IP addresses with a subnet mask. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of IP addresses for which access is prohibited. + - **deny** - List of IP addresses for which access is allowed. + + Examples: + + - `192.168.3.2/32` + - `2a03:d000:2980:7::8/128` + """ + + policy_type: Required[Literal["allow", "deny"]] + """IP access policy type. + + Possible values: + + - **allow** - Allow access to all IPs except IPs specified in "excepted_values" + field. + - **deny** - Deny access to all IPs except IPs specified in "excepted_values" + field. + """ + + +class OptionsLimitBandwidth(TypedDict, total=False): + """Allows to control the download speed per connection.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + limit_type: Required[Literal["static", "dynamic"]] + """Method of controlling the download speed per connection. + + Possible values: + + - **static** - Use speed and buffer fields to set the download speed limit. + - **dynamic** - Use query strings **speed** and **buffer** to set the download + speed limit. + + For example, when requesting content at the link + + ``` + http://cdn.example.com/video.mp4?speed=50k&buffer=500k + ``` + + the download speed will be limited to 50kB/s after 500 kB. + """ + + buffer: int + """Amount of downloaded data after which the user will be rate limited.""" + + speed: int + """Maximum download speed per connection.""" + + +class OptionsProxyCacheKey(TypedDict, total=False): + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will not work. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Key for caching.""" + + +class OptionsProxyCacheMethodsSet(TypedDict, total=False): + """Caching for POST requests along with default GET and HEAD.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsProxyConnectTimeout(TypedDict, total=False): + """The time limit for establishing a connection with the origin.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 5s**. + """ + + +class OptionsProxyReadTimeout(TypedDict, total=False): + """ + The time limit for receiving a partial response from the origin. + If no response is received within this time, the connection will be closed. + + **Note:** + When used with a WebSocket connection, this option supports values only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 30s**. + """ + + +class OptionsQueryParamsBlacklist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as one object, files with other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryParamsWhitelist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as different objects, files with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryStringForwarding(TypedDict, total=False): + """ + The Query String Forwarding feature allows for the seamless transfer of parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication tokens or tracking information, are consistently passed along from the playlist manifest to the individual media segments. + This is particularly useful for maintaining continuity in security, analytics, and any other parameter-based operations across the entire media delivery workflow. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + forward_from_file_types: Required[SequenceNotStr[str]] + """ + The `forward_from_files_types` field specifies the types of playlist files from + which parameters will be extracted and forwarded. This typically includes + formats that list multiple media chunk references, such as HLS and DASH + playlists. Parameters associated with these playlist files (like query strings + or headers) will be propagated to the chunks they reference. + """ + + forward_to_file_types: Required[SequenceNotStr[str]] + """ + The field specifies the types of media chunk files to which parameters, + extracted from playlist files, will be forwarded. These refer to the actual + segments of media content that are delivered to viewers. Ensuring the correct + parameters are forwarded to these files is crucial for maintaining the integrity + of the streaming session. + """ + + forward_except_keys: SequenceNotStr[str] + """ + The `forward_except_keys` field provides a mechanism to exclude specific + parameters from being forwarded from playlist files to media chunk files. By + listing certain keys in this field, you can ensure that these parameters are + omitted during the forwarding process. This is particularly useful for + preventing sensitive or irrelevant information from being included in requests + for media chunks, thereby enhancing security and optimizing performance. + """ + + forward_only_keys: SequenceNotStr[str] + """ + The `forward_only_keys` field allows for granular control over which specific + parameters are forwarded from playlist files to media chunk files. By specifying + certain keys, only those parameters will be propagated, ensuring that only + relevant information is passed along. This is particularly useful for security + and performance optimization, as it prevents unnecessary or sensitive data from + being included in requests for media chunks. + """ + + +class OptionsRedirectHTTPToHTTPS(TypedDict, total=False): + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsRedirectHTTPSToHTTP(TypedDict, total=False): + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsReferrerACL(TypedDict, total=False): + """Controls access to the CDN resource content for specified domain names.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """ + List of domain names or wildcard domains (without protocol: `http://` or + `https://`.) + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of domain names for which access is prohibited. + - **deny** - List of IP domain names for which access is allowed. + + Examples: + + - `example.com` + - `*.example.com` + """ + + policy_type: Required[Literal["allow", "deny"]] + """Policy type. + + Possible values: + + - **allow** - Allow access to all domain names except the domain names specified + in `excepted_values` field. + - **deny** - Deny access to all domain names except the domain names specified + in `excepted_values` field. + """ + + +class OptionsRequestLimiter(TypedDict, total=False): + """Option allows to limit the amount of HTTP requests.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + rate: Required[int] + """Maximum request rate.""" + + rate_unit: Literal["r/s", "r/m"] + """Units of measurement for the `rate` field. + + Possible values: + + - **r/s** - Requests per second. + - **r/m** - Requests per minute. + + If the rate is less than one request per second, it is specified in request per + minute (r/m.) + """ + + +class OptionsResponseHeadersHidingPolicy(TypedDict, total=False): + """Hides HTTP headers from an origin server in the CDN response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted: Required[SequenceNotStr[str]] + """List of HTTP headers. + + Parameter meaning depends on the value of the `mode` field: + + - **show** - List of HTTP headers to hide from response. + - **hide** - List of HTTP headers to include in response. Other HTTP headers + will be hidden. + + The following headers are required and cannot be hidden from response: + + - `Connection` + - `Content-Length` + - `Content-Type` + - `Date` + - `Server` + """ + + mode: Required[Literal["hide", "show"]] + """How HTTP headers are hidden from the response. + + Possible values: + + - **show** - Hide only HTTP headers listed in the `excepted` field. + - **hide** - Hide all HTTP headers except headers listed in the "excepted" + field. + """ + + +class OptionsRewrite(TypedDict, total=False): + """Changes and redirects requests from the CDN to the origin. + + It operates according to the [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) configuration. + """ + + body: Required[str] + """Path for the Rewrite option. + + Example: + + - `/(.*) /media/$1` + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + flag: Literal["break", "last", "redirect", "permanent"] + """Flag for the Rewrite option. + + Possible values: + + - **last** - Stop processing the current set of `ngx_http_rewrite_module` + directives and start a search for a new location matching changed URI. + - **break** - Stop processing the current set of the Rewrite option. + - **redirect** - Return a temporary redirect with the 302 code; used when a + replacement string does not start with `http://`, `https://`, or `$scheme`. + - **permanent** - Return a permanent redirect with the 301 code. + """ + + +class OptionsSecureKey(TypedDict, total=False): + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + key: Required[Optional[str]] + """Key generated on your side that will be used for URL signing.""" + + type: Literal[0, 2] + """Type of URL signing. + + Possible types: + + - **Type 0** - Includes end user IP to secure token generation. + - **Type 2** - Excludes end user IP from secure token generation. + """ + + +class OptionsSlice(TypedDict, total=False): + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per part.) This reduces time to first byte. + + The option is based on the [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` options enabled. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsSni(TypedDict, total=False): + """ + The hostname that is added to SNI requests from CDN servers to the origin server via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not have a dedicated IP address. + If the origin server presents multiple certificates, SNI allows the origin server to know which certificate to use for the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + custom_hostname: Required[str] + """Custom SNI hostname. + + It is required if `sni_type` is set to custom. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + sni_type: Literal["dynamic", "custom"] + """SNI (Server Name Indication) type. + + Possible values: + + - **dynamic** - SNI hostname depends on `hostHeader` and `forward_host_header` + options. It has several possible combinations: + - If the `hostHeader` option is enabled and specified, SNI hostname matches the + Host header. + - If the `forward_host_header` option is enabled and has true value, SNI + hostname matches the Host header used in the request made to a CDN. + - If the `hostHeader` and `forward_host_header` options are disabled, SNI + hostname matches the primary CNAME. + - **custom** - custom SNI hostname is in use. + """ + + +class OptionsStale(TypedDict, total=False): + """Serves stale cached content in case of origin unavailability.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "error", + "http_403", + "http_404", + "http_429", + "http_500", + "http_502", + "http_503", + "http_504", + "invalid_header", + "timeout", + "updating", + ] + ] + ] + """Defines list of errors for which "Always online" option is applied.""" + + +class OptionsStaticResponseHeadersValue(TypedDict, total=False): + name: Required[str] + """HTTP Header name. + + Restrictions: + + - Maximum 128 symbols. + - Latin letters (A-Z, a-z,) numbers (0-9,) dashes, and underscores only. + """ + + value: Required[SequenceNotStr[str]] + """Header value. + + Restrictions: + + - Maximum 512 symbols. + - Letters (a-z), numbers (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ + /|\";:?.,><{}[]). + - Must start with a letter, number, asterisk or {. + - Multiple values can be added. + """ + + always: bool + """ + Defines whether the header will be added to a response from CDN regardless of + response code. + + Possible values: + + - **true** - Header will be added to a response from CDN regardless of response + code. + - **false** - Header will be added only to the following response codes: 200, + 201, 204, 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsStaticResponseHeaders(TypedDict, total=False): + """Custom HTTP Headers that a CDN server adds to a response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Iterable[OptionsStaticResponseHeadersValue]] + + +class OptionsStaticHeaders(TypedDict, total=False): + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP Headers can be specified. May contain a header with multiple values. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[object] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 128 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsStaticRequestHeaders(TypedDict, total=False): + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Dict[str, str]] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 255 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsUserAgentACL(TypedDict, total=False): + """Controls access to the content for specified User-Agents.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of User-Agents that will be allowed/denied. + + The meaning of the parameter depends on `policy_type`: + + - **allow** - List of User-Agents for which access is prohibited. + - **deny** - List of User-Agents for which access is allowed. + + You can provide exact User-Agent strings or regular expressions. Regular + expressions must start with `~` (case-sensitive) or `~*` (case-insensitive). + + Use an empty string `""` to allow/deny access when the User-Agent header is + empty. + """ + + policy_type: Required[Literal["allow", "deny"]] + """User-Agents policy type. + + Possible values: + + - **allow** - Allow access for all User-Agents except specified in + `excepted_values` field. + - **deny** - Deny access for all User-Agents except specified in + `excepted_values` field. + """ + + +class OptionsWaap(TypedDict, total=False): + """Allows to enable WAAP (Web Application and API Protection).""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsWebsockets(TypedDict, total=False): + """Enables or disables WebSockets connections to an origin server.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class Options(TypedDict, total=False): + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. + Option inherits its value from the CDN resource settings. + """ + + allowed_http_methods: Annotated[Optional[OptionsAllowedHTTPMethods], PropertyInfo(alias="allowedHttpMethods")] + """HTTP methods allowed for content requests from the CDN.""" + + bot_protection: Optional[OptionsBotProtection] + """ + Allows to prevent online services from overloading and ensure your business + workflow running smoothly. + """ + + brotli_compression: Optional[OptionsBrotliCompression] + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is + activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, + even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` + options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides + `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN + resource and want to enable `brotli_compression` in a rule, you must specify + `fetch_compressed:false` in the rule. + """ + + browser_cache_settings: Optional[OptionsBrowserCacheSettings] + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + cache_http_headers: Optional[OptionsCacheHTTPHeaders] + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + cors: Optional[OptionsCors] + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header + to a response to a browser. + """ + + country_acl: Optional[OptionsCountryACL] + """Enables control access to content for specified countries.""" + + disable_cache: Optional[OptionsDisableCache] + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + disable_proxy_force_ranges: Optional[OptionsDisableProxyForceRanges] + """Allows 206 responses regardless of the settings of an origin source.""" + + edge_cache_settings: Optional[OptionsEdgeCacheSettings] + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + fastedge: Optional[OptionsFastedge] + """ + Allows to configure FastEdge app to be called on different request/response + phases. + + Note: At least one of `on_request_headers`, `on_request_body`, + `on_response_headers`, or `on_response_body` must be specified. + """ + + fetch_compressed: Optional[OptionsFetchCompressed] + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress + your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or + `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If + you enable it in CDN resource and want to use `gzipON` and + `brotli_compression` in a rule, you have to specify + `"fetch_compressed": false` in the rule. + """ + + follow_origin_redirect: Optional[OptionsFollowOriginRedirect] + """ + Enables redirection from origin. If the origin server returns a redirect, the + option allows the CDN to pull the requested content from the origin server that + was returned in the redirect. + """ + + force_return: Optional[OptionsForceReturn] + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this + option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + forward_host_header: Optional[OptionsForwardHostHeader] + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + gzip_on: Annotated[Optional[OptionsGzipOn], PropertyInfo(alias="gzipOn")] + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` + options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in + rules. If you enable `fetch_compressed` in CDN resource and want to enable + `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + host_header: Annotated[Optional[OptionsHostHeader], PropertyInfo(alias="hostHeader")] + """ + Sets the Host header that CDN servers use when request content from an origin + server. Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + ignore_cookie: Optional[OptionsIgnoreCookie] + """ + Defines whether the files with the Set-Cookies header are cached as one file or + as different ones. + """ + + ignore_query_string: Annotated[Optional[OptionsIgnoreQueryString], PropertyInfo(alias="ignoreQueryString")] + """ + How a file with different query strings is cached: either as one object (option + is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + image_stack: Optional[OptionsImageStack] + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically + converts them to WebP or AVIF format. + """ + + ip_address_acl: Optional[OptionsIPAddressACL] + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, + you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. + [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + limit_bandwidth: Optional[OptionsLimitBandwidth] + """Allows to control the download speed per connection.""" + + proxy_cache_key: Optional[OptionsProxyCacheKey] + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache + and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will + not work. + """ + + proxy_cache_methods_set: Optional[OptionsProxyCacheMethodsSet] + """Caching for POST requests along with default GET and HEAD.""" + + proxy_connect_timeout: Optional[OptionsProxyConnectTimeout] + """The time limit for establishing a connection with the origin.""" + + proxy_read_timeout: Optional[OptionsProxyReadTimeout] + """ + The time limit for receiving a partial response from the origin. If no response + is received within this time, the connection will be closed. + + **Note:** When used with a WebSocket connection, this option supports values + only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + query_params_blacklist: Optional[OptionsQueryParamsBlacklist] + """ + Files with the specified query parameters are cached as one object, files with + other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_params_whitelist: Optional[OptionsQueryParamsWhitelist] + """ + Files with the specified query parameters are cached as different objects, files + with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_string_forwarding: Optional[OptionsQueryStringForwarding] + """ + The Query String Forwarding feature allows for the seamless transfer of + parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication + tokens or tracking information, are consistently passed along from the playlist + manifest to the individual media segments. This is particularly useful for + maintaining continuity in security, analytics, and any other parameter-based + operations across the entire media delivery workflow. + """ + + redirect_http_to_https: Optional[OptionsRedirectHTTPToHTTPS] + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + redirect_https_to_http: Optional[OptionsRedirectHTTPSToHTTP] + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + referrer_acl: Optional[OptionsReferrerACL] + """Controls access to the CDN resource content for specified domain names.""" + + request_limiter: Optional[OptionsRequestLimiter] + """Option allows to limit the amount of HTTP requests.""" + + response_headers_hiding_policy: Optional[OptionsResponseHeadersHidingPolicy] + """Hides HTTP headers from an origin server in the CDN response.""" + + rewrite: Optional[OptionsRewrite] + """Changes and redirects requests from the CDN to the origin. + + It operates according to the + [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) + configuration. + """ + + secure_key: Optional[OptionsSecureKey] + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + slice: Optional[OptionsSlice] + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per + part.) This reduces time to first byte. + + The option is based on the + [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` + options enabled. + """ + + sni: Optional[OptionsSni] + """ + The hostname that is added to SNI requests from CDN servers to the origin server + via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not + have a dedicated IP address. If the origin server presents multiple + certificates, SNI allows the origin server to know which certificate to use for + the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + stale: Optional[OptionsStale] + """Serves stale cached content in case of origin unavailability.""" + + static_response_headers: Optional[OptionsStaticResponseHeaders] + """Custom HTTP Headers that a CDN server adds to a response.""" + + static_headers: Annotated[Optional[OptionsStaticHeaders], PropertyInfo(alias="staticHeaders")] + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP + Headers can be specified. May contain a header with multiple values. + """ + + static_request_headers: Annotated[Optional[OptionsStaticRequestHeaders], PropertyInfo(alias="staticRequestHeaders")] + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + user_agent_acl: Optional[OptionsUserAgentACL] + """Controls access to the content for specified User-Agents.""" + + waap: Optional[OptionsWaap] + """Allows to enable WAAP (Web Application and API Protection).""" + + websockets: Optional[OptionsWebsockets] + """Enables or disables WebSockets connections to an origin server.""" diff --git a/src/gcore/types/cdn/cdn_resources/rule_update_params.py b/src/gcore/types/cdn/cdn_resources/rule_update_params.py new file mode 100644 index 00000000..b98453ba --- /dev/null +++ b/src/gcore/types/cdn/cdn_resources/rule_update_params.py @@ -0,0 +1,1942 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable, Optional +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ...._types import SequenceNotStr +from ...._utils import PropertyInfo + +__all__ = [ + "RuleUpdateParams", + "Options", + "OptionsAllowedHTTPMethods", + "OptionsBotProtection", + "OptionsBotProtectionBotChallenge", + "OptionsBrotliCompression", + "OptionsBrowserCacheSettings", + "OptionsCacheHTTPHeaders", + "OptionsCors", + "OptionsCountryACL", + "OptionsDisableCache", + "OptionsDisableProxyForceRanges", + "OptionsEdgeCacheSettings", + "OptionsFastedge", + "OptionsFastedgeOnRequestBody", + "OptionsFastedgeOnRequestHeaders", + "OptionsFastedgeOnResponseBody", + "OptionsFastedgeOnResponseHeaders", + "OptionsFetchCompressed", + "OptionsFollowOriginRedirect", + "OptionsForceReturn", + "OptionsForceReturnTimeInterval", + "OptionsForwardHostHeader", + "OptionsGzipOn", + "OptionsHostHeader", + "OptionsIgnoreCookie", + "OptionsIgnoreQueryString", + "OptionsImageStack", + "OptionsIPAddressACL", + "OptionsLimitBandwidth", + "OptionsProxyCacheKey", + "OptionsProxyCacheMethodsSet", + "OptionsProxyConnectTimeout", + "OptionsProxyReadTimeout", + "OptionsQueryParamsBlacklist", + "OptionsQueryParamsWhitelist", + "OptionsQueryStringForwarding", + "OptionsRedirectHTTPToHTTPS", + "OptionsRedirectHTTPSToHTTP", + "OptionsReferrerACL", + "OptionsRequestLimiter", + "OptionsResponseHeadersHidingPolicy", + "OptionsRewrite", + "OptionsSecureKey", + "OptionsSlice", + "OptionsSni", + "OptionsStale", + "OptionsStaticResponseHeaders", + "OptionsStaticResponseHeadersValue", + "OptionsStaticHeaders", + "OptionsStaticRequestHeaders", + "OptionsUserAgentACL", + "OptionsWaap", + "OptionsWebsockets", +] + + +class RuleUpdateParams(TypedDict, total=False): + resource_id: Required[int] + + active: bool + """Enables or disables a rule. + + Possible values: + + - **true** - Rule is active, rule settings are applied. + - **false** - Rule is inactive, rule settings are not applied. + """ + + name: str + """Rule name.""" + + options: Options + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + """ + + origin_group: Annotated[Optional[int], PropertyInfo(alias="originGroup")] + """ID of the origin group to which the rule is applied. + + If the origin group is not specified, the rule is applied to the origin group + that the CDN resource is associated with. + """ + + override_origin_protocol: Annotated[ + Optional[Literal["HTTPS", "HTTP", "MATCH"]], PropertyInfo(alias="overrideOriginProtocol") + ] + """ + Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + """ + + rule: str + """Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + """ + + rule_type: Annotated[int, PropertyInfo(alias="ruleType")] + """Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + """ + + weight: int + """Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + """ + + +class OptionsAllowedHTTPMethods(TypedDict, total=False): + """HTTP methods allowed for content requests from the CDN.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[List[Literal["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]]] + + +class OptionsBotProtectionBotChallenge(TypedDict, total=False): + """Controls the bot challenge module state.""" + + enabled: bool + """Possible values: + + - **true** - Bot challenge is enabled. + - **false** - Bot challenge is disabled. + """ + + +class OptionsBotProtection(TypedDict, total=False): + """ + Allows to prevent online services from overloading and ensure your business workflow running smoothly. + """ + + bot_challenge: Required[OptionsBotProtectionBotChallenge] + """Controls the bot challenge module state.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsBrotliCompression(TypedDict, total=False): + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN resource and want to enable `brotli_compression` in a rule, you must specify `fetch_compressed:false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "application/javascript", + "application/json", + "application/vnd.ms-fontobject", + "application/wasm", + "application/x-font-ttf", + "application/x-javascript", + "application/xml", + "application/xml+rss", + "image/svg+xml", + "image/x-icon", + "text/css", + "text/html", + "text/javascript", + "text/plain", + "text/xml", + ] + ] + ] + """Allows to select the content types you want to compress. + + `text/html` is a mandatory content type. + """ + + +class OptionsBrowserCacheSettings(TypedDict, total=False): + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Set the cache expiration time to '0s' to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsCacheHTTPHeaders(TypedDict, total=False): + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + + +class OptionsCors(TypedDict, total=False): + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header to a response to a browser. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """Value of the Access-Control-Allow-Origin header. + + Possible values: + + - **Adds \\** as the Access-Control-Allow-Origin header value** - Content will be + uploaded for requests from any domain. `"value": ["*"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value if the + origin matches one of the listed domains** - Content will be uploaded only for + requests from the domains specified in the field. + `"value": ["domain.com", "second.dom.com"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value** - + Content will be uploaded for requests from any domain, and the domain from + which the request was sent will be added to the "Access-Control-Allow-Origin" + header in the response. `"value": ["$http_origin"]` + """ + + always: bool + """ + Defines whether the Access-Control-Allow-Origin header should be added to a + response from CDN regardless of response code. + + Possible values: + + - **true** - Header will be added to a response regardless of response code. + - **false** - Header will only be added to responses with codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsCountryACL(TypedDict, total=False): + """Enables control access to content for specified countries.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of countries according to ISO-3166-1. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of countries for which access is prohibited. + - **deny** - List of countries for which access is allowed. + """ + + policy_type: Required[Literal["allow", "deny"]] + """Defines the type of CDN resource access policy. + + Possible values: + + - **allow** - Access is allowed for all the countries except for those specified + in `excepted_values` field. + - **deny** - Access is denied for all the countries except for those specified + in `excepted_values` field. + """ + + +class OptionsDisableCache(TypedDict, total=False): + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - content caching is disabled. + - **false** - content caching is enabled. + """ + + +class OptionsDisableProxyForceRanges(TypedDict, total=False): + """Allows 206 responses regardless of the settings of an origin source.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsEdgeCacheSettings(TypedDict, total=False): + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + custom_values: Dict[str, str] + """ + A MAP object representing the caching time in seconds for a response with a + specific response code. + + These settings have a higher priority than the `value` field. + + - Use `any` key to specify caching time for all response codes. + - Use `0s` value to disable caching for a specific response code. + """ + + default: str + """Enables content caching according to the origin cache settings. + + The value is applied to the following response codes 200, 201, 204, 206, 301, + 302, 303, 304, 307, 308, if an origin server does not have caching HTTP headers. + + Responses with other codes will not be cached. + + The maximum duration is any equivalent to `1y`. + """ + + value: str + """Caching time. + + The value is applied to the following response codes: 200, 206, 301, 302. + Responses with codes 4xx, 5xx will not be cached. + + Use `0s` to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsFastedgeOnRequestBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request body as soon as CDN receives incoming HTTP request. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnRequestHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response body before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response headers before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedge(TypedDict, total=False): + """ + Allows to configure FastEdge app to be called on different request/response phases. + + Note: At least one of `on_request_headers`, `on_request_body`, `on_response_headers`, or `on_response_body` must be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + on_request_body: OptionsFastedgeOnRequestBody + """ + Allows to configure FastEdge application that will be called to handle request + body as soon as CDN receives incoming HTTP request. + """ + + on_request_headers: OptionsFastedgeOnRequestHeaders + """ + Allows to configure FastEdge application that will be called to handle request + headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + on_response_body: OptionsFastedgeOnResponseBody + """ + Allows to configure FastEdge application that will be called to handle response + body before CDN sends the HTTP response. + """ + + on_response_headers: OptionsFastedgeOnResponseHeaders + """ + Allows to configure FastEdge application that will be called to handle response + headers before CDN sends the HTTP response. + """ + + +class OptionsFetchCompressed(TypedDict, total=False): + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If you enable it in CDN resource and want to use `gzipON` and `brotli_compression` in a rule, you have to specify `"fetch_compressed": false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsFollowOriginRedirect(TypedDict, total=False): + """ + Enables redirection from origin. + If the origin server returns a redirect, the option allows the CDN to pull the requested content from the origin server that was returned in the redirect. + """ + + codes: Required[Iterable[Literal[301, 302, 303, 307, 308]]] + """Redirect status code that the origin server returns. + + To serve up to date content to end users, you will need to purge the cache after + managing the option. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsForceReturnTimeInterval(TypedDict, total=False): + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + end_time: Required[str] + """Time until which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + start_time: Required[str] + """Time from which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + time_zone: str + """Time zone used to calculate time.""" + + +class OptionsForceReturn(TypedDict, total=False): + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + body: Required[str] + """URL for redirection or text.""" + + code: Required[int] + """Status code value.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + time_interval: Optional[OptionsForceReturnTimeInterval] + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + +class OptionsForwardHostHeader(TypedDict, total=False): + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsGzipOn(TypedDict, total=False): + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in rules. If you enable `fetch_compressed` in CDN resource and want to enable `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsHostHeader(TypedDict, total=False): + """ + Sets the Host header that CDN servers use when request content from an origin server. + Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Host Header value.""" + + +class OptionsIgnoreCookie(TypedDict, total=False): + """ + Defines whether the files with the Set-Cookies header are cached as one file or as different ones. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled, files with cookies are cached as one file. + - **false** - Option is disabled, files with cookies are cached as different + files. + """ + + +class OptionsIgnoreQueryString(TypedDict, total=False): + """ + How a file with different query strings is cached: either as one object (option is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsImageStack(TypedDict, total=False): + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically converts them to WebP or AVIF format. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + avif_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to AVI format.""" + + png_lossless: bool + """Enables or disables compression without quality loss for PNG format.""" + + quality: int + """Defines quality settings for JPG and PNG images. + + The higher the value, the better the image quality, and the larger the file size + after conversion. + """ + + webp_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to WebP format.""" + + +class OptionsIPAddressACL(TypedDict, total=False): + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of IP addresses with a subnet mask. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of IP addresses for which access is prohibited. + - **deny** - List of IP addresses for which access is allowed. + + Examples: + + - `192.168.3.2/32` + - `2a03:d000:2980:7::8/128` + """ + + policy_type: Required[Literal["allow", "deny"]] + """IP access policy type. + + Possible values: + + - **allow** - Allow access to all IPs except IPs specified in "excepted_values" + field. + - **deny** - Deny access to all IPs except IPs specified in "excepted_values" + field. + """ + + +class OptionsLimitBandwidth(TypedDict, total=False): + """Allows to control the download speed per connection.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + limit_type: Required[Literal["static", "dynamic"]] + """Method of controlling the download speed per connection. + + Possible values: + + - **static** - Use speed and buffer fields to set the download speed limit. + - **dynamic** - Use query strings **speed** and **buffer** to set the download + speed limit. + + For example, when requesting content at the link + + ``` + http://cdn.example.com/video.mp4?speed=50k&buffer=500k + ``` + + the download speed will be limited to 50kB/s after 500 kB. + """ + + buffer: int + """Amount of downloaded data after which the user will be rate limited.""" + + speed: int + """Maximum download speed per connection.""" + + +class OptionsProxyCacheKey(TypedDict, total=False): + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will not work. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Key for caching.""" + + +class OptionsProxyCacheMethodsSet(TypedDict, total=False): + """Caching for POST requests along with default GET and HEAD.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsProxyConnectTimeout(TypedDict, total=False): + """The time limit for establishing a connection with the origin.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 5s**. + """ + + +class OptionsProxyReadTimeout(TypedDict, total=False): + """ + The time limit for receiving a partial response from the origin. + If no response is received within this time, the connection will be closed. + + **Note:** + When used with a WebSocket connection, this option supports values only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 30s**. + """ + + +class OptionsQueryParamsBlacklist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as one object, files with other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryParamsWhitelist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as different objects, files with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryStringForwarding(TypedDict, total=False): + """ + The Query String Forwarding feature allows for the seamless transfer of parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication tokens or tracking information, are consistently passed along from the playlist manifest to the individual media segments. + This is particularly useful for maintaining continuity in security, analytics, and any other parameter-based operations across the entire media delivery workflow. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + forward_from_file_types: Required[SequenceNotStr[str]] + """ + The `forward_from_files_types` field specifies the types of playlist files from + which parameters will be extracted and forwarded. This typically includes + formats that list multiple media chunk references, such as HLS and DASH + playlists. Parameters associated with these playlist files (like query strings + or headers) will be propagated to the chunks they reference. + """ + + forward_to_file_types: Required[SequenceNotStr[str]] + """ + The field specifies the types of media chunk files to which parameters, + extracted from playlist files, will be forwarded. These refer to the actual + segments of media content that are delivered to viewers. Ensuring the correct + parameters are forwarded to these files is crucial for maintaining the integrity + of the streaming session. + """ + + forward_except_keys: SequenceNotStr[str] + """ + The `forward_except_keys` field provides a mechanism to exclude specific + parameters from being forwarded from playlist files to media chunk files. By + listing certain keys in this field, you can ensure that these parameters are + omitted during the forwarding process. This is particularly useful for + preventing sensitive or irrelevant information from being included in requests + for media chunks, thereby enhancing security and optimizing performance. + """ + + forward_only_keys: SequenceNotStr[str] + """ + The `forward_only_keys` field allows for granular control over which specific + parameters are forwarded from playlist files to media chunk files. By specifying + certain keys, only those parameters will be propagated, ensuring that only + relevant information is passed along. This is particularly useful for security + and performance optimization, as it prevents unnecessary or sensitive data from + being included in requests for media chunks. + """ + + +class OptionsRedirectHTTPToHTTPS(TypedDict, total=False): + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsRedirectHTTPSToHTTP(TypedDict, total=False): + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsReferrerACL(TypedDict, total=False): + """Controls access to the CDN resource content for specified domain names.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """ + List of domain names or wildcard domains (without protocol: `http://` or + `https://`.) + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of domain names for which access is prohibited. + - **deny** - List of IP domain names for which access is allowed. + + Examples: + + - `example.com` + - `*.example.com` + """ + + policy_type: Required[Literal["allow", "deny"]] + """Policy type. + + Possible values: + + - **allow** - Allow access to all domain names except the domain names specified + in `excepted_values` field. + - **deny** - Deny access to all domain names except the domain names specified + in `excepted_values` field. + """ + + +class OptionsRequestLimiter(TypedDict, total=False): + """Option allows to limit the amount of HTTP requests.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + rate: Required[int] + """Maximum request rate.""" + + rate_unit: Literal["r/s", "r/m"] + """Units of measurement for the `rate` field. + + Possible values: + + - **r/s** - Requests per second. + - **r/m** - Requests per minute. + + If the rate is less than one request per second, it is specified in request per + minute (r/m.) + """ + + +class OptionsResponseHeadersHidingPolicy(TypedDict, total=False): + """Hides HTTP headers from an origin server in the CDN response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted: Required[SequenceNotStr[str]] + """List of HTTP headers. + + Parameter meaning depends on the value of the `mode` field: + + - **show** - List of HTTP headers to hide from response. + - **hide** - List of HTTP headers to include in response. Other HTTP headers + will be hidden. + + The following headers are required and cannot be hidden from response: + + - `Connection` + - `Content-Length` + - `Content-Type` + - `Date` + - `Server` + """ + + mode: Required[Literal["hide", "show"]] + """How HTTP headers are hidden from the response. + + Possible values: + + - **show** - Hide only HTTP headers listed in the `excepted` field. + - **hide** - Hide all HTTP headers except headers listed in the "excepted" + field. + """ + + +class OptionsRewrite(TypedDict, total=False): + """Changes and redirects requests from the CDN to the origin. + + It operates according to the [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) configuration. + """ + + body: Required[str] + """Path for the Rewrite option. + + Example: + + - `/(.*) /media/$1` + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + flag: Literal["break", "last", "redirect", "permanent"] + """Flag for the Rewrite option. + + Possible values: + + - **last** - Stop processing the current set of `ngx_http_rewrite_module` + directives and start a search for a new location matching changed URI. + - **break** - Stop processing the current set of the Rewrite option. + - **redirect** - Return a temporary redirect with the 302 code; used when a + replacement string does not start with `http://`, `https://`, or `$scheme`. + - **permanent** - Return a permanent redirect with the 301 code. + """ + + +class OptionsSecureKey(TypedDict, total=False): + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + key: Required[Optional[str]] + """Key generated on your side that will be used for URL signing.""" + + type: Literal[0, 2] + """Type of URL signing. + + Possible types: + + - **Type 0** - Includes end user IP to secure token generation. + - **Type 2** - Excludes end user IP from secure token generation. + """ + + +class OptionsSlice(TypedDict, total=False): + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per part.) This reduces time to first byte. + + The option is based on the [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` options enabled. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsSni(TypedDict, total=False): + """ + The hostname that is added to SNI requests from CDN servers to the origin server via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not have a dedicated IP address. + If the origin server presents multiple certificates, SNI allows the origin server to know which certificate to use for the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + custom_hostname: Required[str] + """Custom SNI hostname. + + It is required if `sni_type` is set to custom. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + sni_type: Literal["dynamic", "custom"] + """SNI (Server Name Indication) type. + + Possible values: + + - **dynamic** - SNI hostname depends on `hostHeader` and `forward_host_header` + options. It has several possible combinations: + - If the `hostHeader` option is enabled and specified, SNI hostname matches the + Host header. + - If the `forward_host_header` option is enabled and has true value, SNI + hostname matches the Host header used in the request made to a CDN. + - If the `hostHeader` and `forward_host_header` options are disabled, SNI + hostname matches the primary CNAME. + - **custom** - custom SNI hostname is in use. + """ + + +class OptionsStale(TypedDict, total=False): + """Serves stale cached content in case of origin unavailability.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "error", + "http_403", + "http_404", + "http_429", + "http_500", + "http_502", + "http_503", + "http_504", + "invalid_header", + "timeout", + "updating", + ] + ] + ] + """Defines list of errors for which "Always online" option is applied.""" + + +class OptionsStaticResponseHeadersValue(TypedDict, total=False): + name: Required[str] + """HTTP Header name. + + Restrictions: + + - Maximum 128 symbols. + - Latin letters (A-Z, a-z,) numbers (0-9,) dashes, and underscores only. + """ + + value: Required[SequenceNotStr[str]] + """Header value. + + Restrictions: + + - Maximum 512 symbols. + - Letters (a-z), numbers (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ + /|\";:?.,><{}[]). + - Must start with a letter, number, asterisk or {. + - Multiple values can be added. + """ + + always: bool + """ + Defines whether the header will be added to a response from CDN regardless of + response code. + + Possible values: + + - **true** - Header will be added to a response from CDN regardless of response + code. + - **false** - Header will be added only to the following response codes: 200, + 201, 204, 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsStaticResponseHeaders(TypedDict, total=False): + """Custom HTTP Headers that a CDN server adds to a response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Iterable[OptionsStaticResponseHeadersValue]] + + +class OptionsStaticHeaders(TypedDict, total=False): + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP Headers can be specified. May contain a header with multiple values. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[object] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 128 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsStaticRequestHeaders(TypedDict, total=False): + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Dict[str, str]] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 255 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsUserAgentACL(TypedDict, total=False): + """Controls access to the content for specified User-Agents.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of User-Agents that will be allowed/denied. + + The meaning of the parameter depends on `policy_type`: + + - **allow** - List of User-Agents for which access is prohibited. + - **deny** - List of User-Agents for which access is allowed. + + You can provide exact User-Agent strings or regular expressions. Regular + expressions must start with `~` (case-sensitive) or `~*` (case-insensitive). + + Use an empty string `""` to allow/deny access when the User-Agent header is + empty. + """ + + policy_type: Required[Literal["allow", "deny"]] + """User-Agents policy type. + + Possible values: + + - **allow** - Allow access for all User-Agents except specified in + `excepted_values` field. + - **deny** - Deny access for all User-Agents except specified in + `excepted_values` field. + """ + + +class OptionsWaap(TypedDict, total=False): + """Allows to enable WAAP (Web Application and API Protection).""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsWebsockets(TypedDict, total=False): + """Enables or disables WebSockets connections to an origin server.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class Options(TypedDict, total=False): + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. + Option inherits its value from the CDN resource settings. + """ + + allowed_http_methods: Annotated[Optional[OptionsAllowedHTTPMethods], PropertyInfo(alias="allowedHttpMethods")] + """HTTP methods allowed for content requests from the CDN.""" + + bot_protection: Optional[OptionsBotProtection] + """ + Allows to prevent online services from overloading and ensure your business + workflow running smoothly. + """ + + brotli_compression: Optional[OptionsBrotliCompression] + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is + activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, + even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` + options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides + `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN + resource and want to enable `brotli_compression` in a rule, you must specify + `fetch_compressed:false` in the rule. + """ + + browser_cache_settings: Optional[OptionsBrowserCacheSettings] + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + cache_http_headers: Optional[OptionsCacheHTTPHeaders] + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + cors: Optional[OptionsCors] + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header + to a response to a browser. + """ + + country_acl: Optional[OptionsCountryACL] + """Enables control access to content for specified countries.""" + + disable_cache: Optional[OptionsDisableCache] + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + disable_proxy_force_ranges: Optional[OptionsDisableProxyForceRanges] + """Allows 206 responses regardless of the settings of an origin source.""" + + edge_cache_settings: Optional[OptionsEdgeCacheSettings] + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + fastedge: Optional[OptionsFastedge] + """ + Allows to configure FastEdge app to be called on different request/response + phases. + + Note: At least one of `on_request_headers`, `on_request_body`, + `on_response_headers`, or `on_response_body` must be specified. + """ + + fetch_compressed: Optional[OptionsFetchCompressed] + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress + your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or + `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If + you enable it in CDN resource and want to use `gzipON` and + `brotli_compression` in a rule, you have to specify + `"fetch_compressed": false` in the rule. + """ + + follow_origin_redirect: Optional[OptionsFollowOriginRedirect] + """ + Enables redirection from origin. If the origin server returns a redirect, the + option allows the CDN to pull the requested content from the origin server that + was returned in the redirect. + """ + + force_return: Optional[OptionsForceReturn] + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this + option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + forward_host_header: Optional[OptionsForwardHostHeader] + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + gzip_on: Annotated[Optional[OptionsGzipOn], PropertyInfo(alias="gzipOn")] + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` + options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in + rules. If you enable `fetch_compressed` in CDN resource and want to enable + `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + host_header: Annotated[Optional[OptionsHostHeader], PropertyInfo(alias="hostHeader")] + """ + Sets the Host header that CDN servers use when request content from an origin + server. Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + ignore_cookie: Optional[OptionsIgnoreCookie] + """ + Defines whether the files with the Set-Cookies header are cached as one file or + as different ones. + """ + + ignore_query_string: Annotated[Optional[OptionsIgnoreQueryString], PropertyInfo(alias="ignoreQueryString")] + """ + How a file with different query strings is cached: either as one object (option + is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + image_stack: Optional[OptionsImageStack] + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically + converts them to WebP or AVIF format. + """ + + ip_address_acl: Optional[OptionsIPAddressACL] + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, + you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. + [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + limit_bandwidth: Optional[OptionsLimitBandwidth] + """Allows to control the download speed per connection.""" + + proxy_cache_key: Optional[OptionsProxyCacheKey] + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache + and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will + not work. + """ + + proxy_cache_methods_set: Optional[OptionsProxyCacheMethodsSet] + """Caching for POST requests along with default GET and HEAD.""" + + proxy_connect_timeout: Optional[OptionsProxyConnectTimeout] + """The time limit for establishing a connection with the origin.""" + + proxy_read_timeout: Optional[OptionsProxyReadTimeout] + """ + The time limit for receiving a partial response from the origin. If no response + is received within this time, the connection will be closed. + + **Note:** When used with a WebSocket connection, this option supports values + only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + query_params_blacklist: Optional[OptionsQueryParamsBlacklist] + """ + Files with the specified query parameters are cached as one object, files with + other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_params_whitelist: Optional[OptionsQueryParamsWhitelist] + """ + Files with the specified query parameters are cached as different objects, files + with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_string_forwarding: Optional[OptionsQueryStringForwarding] + """ + The Query String Forwarding feature allows for the seamless transfer of + parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication + tokens or tracking information, are consistently passed along from the playlist + manifest to the individual media segments. This is particularly useful for + maintaining continuity in security, analytics, and any other parameter-based + operations across the entire media delivery workflow. + """ + + redirect_http_to_https: Optional[OptionsRedirectHTTPToHTTPS] + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + redirect_https_to_http: Optional[OptionsRedirectHTTPSToHTTP] + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + referrer_acl: Optional[OptionsReferrerACL] + """Controls access to the CDN resource content for specified domain names.""" + + request_limiter: Optional[OptionsRequestLimiter] + """Option allows to limit the amount of HTTP requests.""" + + response_headers_hiding_policy: Optional[OptionsResponseHeadersHidingPolicy] + """Hides HTTP headers from an origin server in the CDN response.""" + + rewrite: Optional[OptionsRewrite] + """Changes and redirects requests from the CDN to the origin. + + It operates according to the + [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) + configuration. + """ + + secure_key: Optional[OptionsSecureKey] + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + slice: Optional[OptionsSlice] + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per + part.) This reduces time to first byte. + + The option is based on the + [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` + options enabled. + """ + + sni: Optional[OptionsSni] + """ + The hostname that is added to SNI requests from CDN servers to the origin server + via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not + have a dedicated IP address. If the origin server presents multiple + certificates, SNI allows the origin server to know which certificate to use for + the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + stale: Optional[OptionsStale] + """Serves stale cached content in case of origin unavailability.""" + + static_response_headers: Optional[OptionsStaticResponseHeaders] + """Custom HTTP Headers that a CDN server adds to a response.""" + + static_headers: Annotated[Optional[OptionsStaticHeaders], PropertyInfo(alias="staticHeaders")] + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP + Headers can be specified. May contain a header with multiple values. + """ + + static_request_headers: Annotated[Optional[OptionsStaticRequestHeaders], PropertyInfo(alias="staticRequestHeaders")] + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + user_agent_acl: Optional[OptionsUserAgentACL] + """Controls access to the content for specified User-Agents.""" + + waap: Optional[OptionsWaap] + """Allows to enable WAAP (Web Application and API Protection).""" + + websockets: Optional[OptionsWebsockets] + """Enables or disables WebSockets connections to an origin server.""" diff --git a/src/gcore/types/cdn/cdn_resources/shield_replace_params.py b/src/gcore/types/cdn/cdn_resources/shield_replace_params.py new file mode 100644 index 00000000..3cc4e963 --- /dev/null +++ b/src/gcore/types/cdn/cdn_resources/shield_replace_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +__all__ = ["ShieldReplaceParams"] + + +class ShieldReplaceParams(TypedDict, total=False): + shielding_pop: Optional[int] + """Shielding location ID. + + If origin shielding is disabled, the parameter value is **null**. + """ diff --git a/src/gcore/types/cdn/cdn_update_account_params.py b/src/gcore/types/cdn/cdn_update_account_params.py new file mode 100644 index 00000000..a103687e --- /dev/null +++ b/src/gcore/types/cdn/cdn_update_account_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["CDNUpdateAccountParams"] + + +class CDNUpdateAccountParams(TypedDict, total=False): + utilization_level: int + """CDN traffic usage limit in gigabytes. + + When the limit is reached, we will send an email notification. + """ diff --git a/src/gcore/types/cdn/certificate_create_params.py b/src/gcore/types/cdn/certificate_create_params.py new file mode 100644 index 00000000..8c17c903 --- /dev/null +++ b/src/gcore/types/cdn/certificate_create_params.py @@ -0,0 +1,51 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Required, Annotated, TypeAlias, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["CertificateCreateParams", "CreateSSlPayload", "LetSEncryptCertificate"] + + +class CreateSSlPayload(TypedDict, total=False): + name: Required[str] + """SSL certificate name. + + It must be unique. + """ + + ssl_certificate: Required[Annotated[str, PropertyInfo(alias="sslCertificate")]] + """Public part of the SSL certificate. + + All chain of the SSL certificate should be added. + """ + + ssl_private_key: Required[Annotated[str, PropertyInfo(alias="sslPrivateKey")]] + """Private key of the SSL certificate.""" + + validate_root_ca: bool + """ + Defines whether to check the SSL certificate for a signature from a trusted + certificate authority. + + Possible values: + + - **true** - SSL certificate must be verified to be signed by a trusted + certificate authority. + - **false** - SSL certificate will not be verified to be signed by a trusted + certificate authority. + """ + + +class LetSEncryptCertificate(TypedDict, total=False): + automated: Required[bool] + """Must be **true** to issue certificate automatically.""" + + name: Required[str] + """SSL certificate name. It must be unique.""" + + +CertificateCreateParams: TypeAlias = Union[CreateSSlPayload, LetSEncryptCertificate] diff --git a/src/gcore/types/cdn/certificate_get_status_params.py b/src/gcore/types/cdn/certificate_get_status_params.py new file mode 100644 index 00000000..ea923341 --- /dev/null +++ b/src/gcore/types/cdn/certificate_get_status_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["CertificateGetStatusParams"] + + +class CertificateGetStatusParams(TypedDict, total=False): + exclude: SequenceNotStr[str] + """Listed fields will be excluded from the response.""" diff --git a/src/gcore/types/cdn/certificate_list_params.py b/src/gcore/types/cdn/certificate_list_params.py new file mode 100644 index 00000000..7474922f --- /dev/null +++ b/src/gcore/types/cdn/certificate_list_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["CertificateListParams"] + + +class CertificateListParams(TypedDict, total=False): + automated: bool + """How the SSL certificate was issued. + + Possible values: + + - **true** – Certificate was issued automatically. + - **false** – Certificate was added by a user. + """ + + resource_id: int + """CDN resource ID for which certificates are requested.""" + + validity_not_after_lte: str + """ + Date and time when the certificate become untrusted (ISO 8601/RFC 3339 format, + UTC.) + + Response will contain only certificates valid until the specified time. + """ diff --git a/src/gcore/types/cdn/certificate_replace_params.py b/src/gcore/types/cdn/certificate_replace_params.py new file mode 100644 index 00000000..8d60c803 --- /dev/null +++ b/src/gcore/types/cdn/certificate_replace_params.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["CertificateReplaceParams"] + + +class CertificateReplaceParams(TypedDict, total=False): + name: Required[str] + """SSL certificate name. + + It must be unique. + """ + + ssl_certificate: Required[Annotated[str, PropertyInfo(alias="sslCertificate")]] + """Public part of the SSL certificate. + + All chain of the SSL certificate should be added. + """ + + ssl_private_key: Required[Annotated[str, PropertyInfo(alias="sslPrivateKey")]] + """Private key of the SSL certificate.""" + + validate_root_ca: bool + """ + Defines whether to check the SSL certificate for a signature from a trusted + certificate authority. + + Possible values: + + - **true** - SSL certificate must be verified to be signed by a trusted + certificate authority. + - **false** - SSL certificate will not be verified to be signed by a trusted + certificate authority. + """ diff --git a/src/gcore/types/cdn/ip_range_list_ips_params.py b/src/gcore/types/cdn/ip_range_list_ips_params.py new file mode 100644 index 00000000..f10f642c --- /dev/null +++ b/src/gcore/types/cdn/ip_range_list_ips_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["IPRangeListIPsParams"] + + +class IPRangeListIPsParams(TypedDict, total=False): + format: Literal["json", "plain"] + """ + Optional format override. When set, this takes precedence over the `Accept` + header. + """ + + accept: Annotated[Literal["application/json", "text/plain"], PropertyInfo(alias="Accept")] diff --git a/src/gcore/types/cdn/ip_range_list_params.py b/src/gcore/types/cdn/ip_range_list_params.py new file mode 100644 index 00000000..2de60645 --- /dev/null +++ b/src/gcore/types/cdn/ip_range_list_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["IPRangeListParams"] + + +class IPRangeListParams(TypedDict, total=False): + format: Literal["json", "plain"] + """ + Optional format override. When set, this takes precedence over the `Accept` + header. + """ + + accept: Annotated[Literal["application/json", "text/plain"], PropertyInfo(alias="Accept")] diff --git a/src/gcore/types/cdn/log_download_params.py b/src/gcore/types/cdn/log_download_params.py new file mode 100644 index 00000000..2804b7bb --- /dev/null +++ b/src/gcore/types/cdn/log_download_params.py @@ -0,0 +1,279 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["LogDownloadParams"] + + +class LogDownloadParams(TypedDict, total=False): + format: Required[str] + """Output format. + + Possible values: + + - csv + - tsv + """ + + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """ + Start date and time of the requested time period (ISO 8601/RFC 3339 format, + UTC.) + + Difference between "from" and "to" cannot exceed 6 hours. + + Examples: + + - &from=2021-06-14T00:00:00Z + - &from=2021-06-14T00:00:00.000Z + """ + + to: Required[str] + """End date and time of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + Difference between "from" and "to" cannot exceed 6 hours. + + Examples: + + - &to=2021-06-15T00:00:00Z + - &to=2021-06-15T00:00:00.000Z + """ + + cache_status_eq: Annotated[str, PropertyInfo(alias="cache_status__eq")] + """Caching status. + + Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', + 'REVALIDATED', 'HIT', '-'. + """ + + cache_status_in: Annotated[str, PropertyInfo(alias="cache_status__in")] + """List of caching statuses. + + Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', + 'REVALIDATED', 'HIT', '-'. Values should be separated by a comma. + """ + + cache_status_ne: Annotated[str, PropertyInfo(alias="cache_status__ne")] + """Caching status not equal to the specified value. + + Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', + 'REVALIDATED', 'HIT', '-'. + """ + + cache_status_not_in: Annotated[str, PropertyInfo(alias="cache_status__not_in")] + """List of caching statuses not equal to the specified values. + + Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', + 'REVALIDATED', 'HIT', '-'. Values should be separated by a comma. + """ + + client_ip_eq: Annotated[str, PropertyInfo(alias="client_ip__eq")] + """IP address of the client who sent the request.""" + + client_ip_in: Annotated[str, PropertyInfo(alias="client_ip__in")] + """List of IP addresses of the clients who sent the request.""" + + client_ip_ne: Annotated[str, PropertyInfo(alias="client_ip__ne")] + """IP address of the client who did not send the request.""" + + client_ip_not_in: Annotated[str, PropertyInfo(alias="client_ip__not_in")] + """List of IP addresses of the clients who did not send the request.""" + + cname_contains: Annotated[str, PropertyInfo(alias="cname__contains")] + """Part of the custom domain of the requested CDN resource. + + Minimum length is 3 characters. + """ + + cname_eq: Annotated[str, PropertyInfo(alias="cname__eq")] + """Custom domain of the requested CDN resource.""" + + cname_in: Annotated[str, PropertyInfo(alias="cname__in")] + """List of custom domains of the requested CDN resource. + + Values should be separated by a comma. + """ + + cname_ne: Annotated[str, PropertyInfo(alias="cname__ne")] + """Custom domain of the requested CDN resource not equal to the specified value.""" + + cname_not_in: Annotated[str, PropertyInfo(alias="cname__not_in")] + """ + List of custom domains of the requested CDN resource not equal to the specified + values. Values should be separated by a comma. + """ + + datacenter_eq: Annotated[str, PropertyInfo(alias="datacenter__eq")] + """Data center where request was processed.""" + + datacenter_in: Annotated[str, PropertyInfo(alias="datacenter__in")] + """List of data centers where request was processed. + + Values should be separated by a comma. + """ + + datacenter_ne: Annotated[str, PropertyInfo(alias="datacenter__ne")] + """Data center where request was not processed.""" + + datacenter_not_in: Annotated[str, PropertyInfo(alias="datacenter__not_in")] + """List of data centers where request was not processed. + + Values should be separated by a comma. + """ + + fields: str + """A comma-separated list of returned fields. + + Supported fields are presented in the responses section. + + Example: + + - &fields=timestamp,path,status + """ + + limit: int + """Maximum number of log records in the response.""" + + method_eq: Annotated[str, PropertyInfo(alias="method__eq")] + """Request HTTP method. + + Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', + 'PUT', 'TRACE'. + """ + + method_in: Annotated[str, PropertyInfo(alias="method__in")] + """Request HTTP method. + + Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', + 'PUT', 'TRACE'. Values should be separated by a comma. + """ + + method_ne: Annotated[str, PropertyInfo(alias="method__ne")] + """Request HTTP method. + + Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', + 'PUT', 'TRACE'. + """ + + method_not_in: Annotated[str, PropertyInfo(alias="method__not_in")] + """Request HTTP method. + + Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', + 'PUT', 'TRACE'. Values should be separated by a comma. + """ + + offset: int + """ + Number of log records to skip starting from the beginning of the requested + period. + """ + + resource_id_eq: Annotated[int, PropertyInfo(alias="resource_id__eq")] + """ID of the requested CDN resource equal to the specified value.""" + + resource_id_gt: Annotated[int, PropertyInfo(alias="resource_id__gt")] + """ID of the requested CDN resource greater than the specified value.""" + + resource_id_gte: Annotated[int, PropertyInfo(alias="resource_id__gte")] + """ID of the requested CDN resource greater than or equal to the specified value.""" + + resource_id_in: Annotated[str, PropertyInfo(alias="resource_id__in")] + """List of IDs of the requested CDN resource. + + Values should be separated by a comma. + """ + + resource_id_lt: Annotated[int, PropertyInfo(alias="resource_id__lt")] + """ID of the requested CDN resource less than the specified value.""" + + resource_id_lte: Annotated[int, PropertyInfo(alias="resource_id__lte")] + """ID of the requested CDN resource less than or equal to the specified value.""" + + resource_id_ne: Annotated[int, PropertyInfo(alias="resource_id__ne")] + """ID of the requested CDN resource not equal to the specified value.""" + + resource_id_not_in: Annotated[str, PropertyInfo(alias="resource_id__not_in")] + """List of IDs of the requested CDN resource not equal to the specified values. + + Values should be separated by a comma. + """ + + size_eq: Annotated[int, PropertyInfo(alias="size__eq")] + """Response size in bytes equal to the specified value.""" + + size_gt: Annotated[int, PropertyInfo(alias="size__gt")] + """Response size in bytes greater than the specified value.""" + + size_gte: Annotated[int, PropertyInfo(alias="size__gte")] + """Response size in bytes greater than or equal to the specified value.""" + + size_in: Annotated[str, PropertyInfo(alias="size__in")] + """List of response sizes in bytes. Values should be separated by a comma.""" + + size_lt: Annotated[int, PropertyInfo(alias="size__lt")] + """Response size in bytes less than the specified value.""" + + size_lte: Annotated[int, PropertyInfo(alias="size__lte")] + """Response size in bytes less than or equal to the specified value.""" + + size_ne: Annotated[int, PropertyInfo(alias="size__ne")] + """Response size in bytes not equal to the specified value.""" + + size_not_in: Annotated[str, PropertyInfo(alias="size__not_in")] + """List of response sizes in bytes not equal to the specified values. + + Values should be separated by + """ + + sort: str + """Sorting rules. + + Possible values: + + - **method** - Request HTTP method. + - **`client_ip`** - IP address of the client who sent the request. + - **status** - Status code in the response. + - **size** - Response size in bytes. + - **cname** - Custom domain of the requested resource. + - **`resource_id`** - ID of the requested CDN resource. + - **`cache_status`** - Caching status. + - **datacenter** - Data center where request was processed. + - **timestamp** - Date and time when the request was made. + + May include multiple values separated by a comma. + + Example: + + - &sort=-timestamp,status + """ + + status_eq: Annotated[int, PropertyInfo(alias="status__eq")] + """Status code in the response equal to the specified value.""" + + status_gt: Annotated[int, PropertyInfo(alias="status__gt")] + """Status code in the response greater than the specified value.""" + + status_gte: Annotated[int, PropertyInfo(alias="status__gte")] + """Status code in the response greater than or equal to the specified value.""" + + status_in: Annotated[str, PropertyInfo(alias="status__in")] + """List of status codes in the response. Values should be separated by a comma.""" + + status_lt: Annotated[int, PropertyInfo(alias="status__lt")] + """Status code in the response less than the specified value.""" + + status_lte: Annotated[int, PropertyInfo(alias="status__lte")] + """Status code in the response less than or equal to the specified value.""" + + status_ne: Annotated[int, PropertyInfo(alias="status__ne")] + """Status code in the response not equal to the specified value.""" + + status_not_in: Annotated[str, PropertyInfo(alias="status__not_in")] + """List of status codes not in the response. + + Values should be separated by a comma. + """ diff --git a/src/gcore/types/cdn/log_list_params.py b/src/gcore/types/cdn/log_list_params.py new file mode 100644 index 00000000..7a9b1aca --- /dev/null +++ b/src/gcore/types/cdn/log_list_params.py @@ -0,0 +1,273 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["LogListParams"] + + +class LogListParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """ + Start date and time of the requested time period (ISO 8601/RFC 3339 format, + UTC.) + + Difference between "from" and "to" cannot exceed 6 hours. + + Examples: + + - &from=2021-06-14T00:00:00Z + - &from=2021-06-14T00:00:00.000Z + """ + + to: Required[str] + """End date and time of the requested time period (ISO 8601/RFC 3339 format, UTC.) + + Difference between "from" and "to" cannot exceed 6 hours. + + Examples: + + - &to=2021-06-15T00:00:00Z + - &to=2021-06-15T00:00:00.000Z + """ + + cache_status_eq: Annotated[str, PropertyInfo(alias="cache_status__eq")] + """Caching status. + + Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', + 'REVALIDATED', 'HIT', '-'. + """ + + cache_status_in: Annotated[str, PropertyInfo(alias="cache_status__in")] + """List of caching statuses. + + Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', + 'REVALIDATED', 'HIT', '-'. Values should be separated by a comma. + """ + + cache_status_ne: Annotated[str, PropertyInfo(alias="cache_status__ne")] + """Caching status not equal to the specified value. + + Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', + 'REVALIDATED', 'HIT', '-'. + """ + + cache_status_not_in: Annotated[str, PropertyInfo(alias="cache_status__not_in")] + """List of caching statuses not equal to the specified values. + + Possible values: 'MISS', 'BYPASS', 'EXPIRED', 'STALE', 'PENDING', 'UPDATING', + 'REVALIDATED', 'HIT', '-'. Values should be separated by a comma. + """ + + client_ip_eq: Annotated[str, PropertyInfo(alias="client_ip__eq")] + """IP address of the client who sent the request.""" + + client_ip_in: Annotated[str, PropertyInfo(alias="client_ip__in")] + """List of IP addresses of the clients who sent the request.""" + + client_ip_ne: Annotated[str, PropertyInfo(alias="client_ip__ne")] + """IP address of the client who did not send the request.""" + + client_ip_not_in: Annotated[str, PropertyInfo(alias="client_ip__not_in")] + """List of IP addresses of the clients who did not send the request.""" + + cname_contains: Annotated[str, PropertyInfo(alias="cname__contains")] + """Part of the custom domain of the requested CDN resource. + + Minimum length is 3 characters. + """ + + cname_eq: Annotated[str, PropertyInfo(alias="cname__eq")] + """Custom domain of the requested CDN resource.""" + + cname_in: Annotated[str, PropertyInfo(alias="cname__in")] + """List of custom domains of the requested CDN resource. + + Values should be separated by a comma. + """ + + cname_ne: Annotated[str, PropertyInfo(alias="cname__ne")] + """Custom domain of the requested CDN resource not equal to the specified value.""" + + cname_not_in: Annotated[str, PropertyInfo(alias="cname__not_in")] + """ + List of custom domains of the requested CDN resource not equal to the specified + values. Values should be separated by a comma. + """ + + datacenter_eq: Annotated[str, PropertyInfo(alias="datacenter__eq")] + """Data center where request was processed.""" + + datacenter_in: Annotated[str, PropertyInfo(alias="datacenter__in")] + """List of data centers where request was processed. + + Values should be separated by a comma. + """ + + datacenter_ne: Annotated[str, PropertyInfo(alias="datacenter__ne")] + """Data center where request was not processed.""" + + datacenter_not_in: Annotated[str, PropertyInfo(alias="datacenter__not_in")] + """List of data centers where request was not processed. + + Values should be separated by a comma. + """ + + fields: str + """A comma-separated list of returned fields. + + Supported fields are presented in the responses section. + + Example: + + - &fields=timestamp,path,status + """ + + limit: int + """Maximum number of log records in the response.""" + + method_eq: Annotated[str, PropertyInfo(alias="method__eq")] + """Request HTTP method. + + Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', + 'PUT', 'TRACE'. + """ + + method_in: Annotated[str, PropertyInfo(alias="method__in")] + """Request HTTP method. + + Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', + 'PUT', 'TRACE'. Values should be separated by a comma. + """ + + method_ne: Annotated[str, PropertyInfo(alias="method__ne")] + """Request HTTP method. + + Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', + 'PUT', 'TRACE'. + """ + + method_not_in: Annotated[str, PropertyInfo(alias="method__not_in")] + """Request HTTP method. + + Possible values: 'CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', + 'PUT', 'TRACE'. Values should be separated by a comma. + """ + + offset: int + """ + Number of log records to skip starting from the beginning of the requested + period. + """ + + ordering: str + """Sorting rules. + + Possible values: + + - **method** - Request HTTP method. + - **`client_ip`** - IP address of the client who sent the request. + - **status** - Status code in the response. + - **size** - Response size in bytes. + - **cname** - Custom domain of the requested resource. + - **`resource_id`** - ID of the requested CDN resource. + - **`cache_status`** - Caching status. + - **datacenter** - Data center where request was processed. + - **timestamp** - Date and time when the request was made. + + Parameter may have multiple values separated by a comma. + + By default, ascending sorting is applied. To sort in descending order, add '-' + prefix. + + Example: + + - &ordering=-timestamp,status + """ + + resource_id_eq: Annotated[int, PropertyInfo(alias="resource_id__eq")] + """ID of the requested CDN resource equal to the specified value.""" + + resource_id_gt: Annotated[int, PropertyInfo(alias="resource_id__gt")] + """ID of the requested CDN resource greater than the specified value.""" + + resource_id_gte: Annotated[int, PropertyInfo(alias="resource_id__gte")] + """ID of the requested CDN resource greater than or equal to the specified value.""" + + resource_id_in: Annotated[str, PropertyInfo(alias="resource_id__in")] + """List of IDs of the requested CDN resource. + + Values should be separated by a comma. + """ + + resource_id_lt: Annotated[int, PropertyInfo(alias="resource_id__lt")] + """ID of the requested CDN resource less than the specified value.""" + + resource_id_lte: Annotated[int, PropertyInfo(alias="resource_id__lte")] + """ID of the requested CDN resource less than or equal to the specified value.""" + + resource_id_ne: Annotated[int, PropertyInfo(alias="resource_id__ne")] + """ID of the requested CDN resource not equal to the specified value.""" + + resource_id_not_in: Annotated[str, PropertyInfo(alias="resource_id__not_in")] + """List of IDs of the requested CDN resource not equal to the specified values. + + Values should be separated by a comma. + """ + + size_eq: Annotated[int, PropertyInfo(alias="size__eq")] + """Response size in bytes equal to the specified value.""" + + size_gt: Annotated[int, PropertyInfo(alias="size__gt")] + """Response size in bytes greater than the specified value.""" + + size_gte: Annotated[int, PropertyInfo(alias="size__gte")] + """Response size in bytes greater than or equal to the specified value.""" + + size_in: Annotated[str, PropertyInfo(alias="size__in")] + """List of response sizes in bytes. Values should be separated by a comma.""" + + size_lt: Annotated[int, PropertyInfo(alias="size__lt")] + """Response size in bytes less than the specified value.""" + + size_lte: Annotated[int, PropertyInfo(alias="size__lte")] + """Response size in bytes less than or equal to the specified value.""" + + size_ne: Annotated[int, PropertyInfo(alias="size__ne")] + """Response size in bytes not equal to the specified value.""" + + size_not_in: Annotated[str, PropertyInfo(alias="size__not_in")] + """List of response sizes in bytes not equal to the specified values. + + Values should be separated by + """ + + status_eq: Annotated[int, PropertyInfo(alias="status__eq")] + """Status code in the response equal to the specified value.""" + + status_gt: Annotated[int, PropertyInfo(alias="status__gt")] + """Status code in the response greater than the specified value.""" + + status_gte: Annotated[int, PropertyInfo(alias="status__gte")] + """Status code in the response greater than or equal to the specified value.""" + + status_in: Annotated[str, PropertyInfo(alias="status__in")] + """List of status codes in the response. Values should be separated by a comma.""" + + status_lt: Annotated[int, PropertyInfo(alias="status__lt")] + """Status code in the response less than the specified value.""" + + status_lte: Annotated[int, PropertyInfo(alias="status__lte")] + """Status code in the response less than or equal to the specified value.""" + + status_ne: Annotated[int, PropertyInfo(alias="status__ne")] + """Status code in the response not equal to the specified value.""" + + status_not_in: Annotated[str, PropertyInfo(alias="status__not_in")] + """List of status codes not in the response. + + Values should be separated by a comma. + """ diff --git a/src/gcore/types/cdn/logs_aggregated_stats.py b/src/gcore/types/cdn/logs_aggregated_stats.py new file mode 100644 index 00000000..4fd29679 --- /dev/null +++ b/src/gcore/types/cdn/logs_aggregated_stats.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["LogsAggregatedStats"] + + +class LogsAggregatedStats(BaseModel): + api_1_example: Optional[object] = FieldInfo(alias="1 (example)", default=None) + """CDN resource ID for which statistics data is shown.""" + + metrics: Optional[object] = None + """Statistics parameters.""" + + raw_logs_usage: Optional[str] = None + """Number of resources that used Logs uploader.""" + + resource: Optional[object] = None + """Resources IDs by which statistics data is grouped..""" diff --git a/src/gcore/types/cdn/logs_uploader/__init__.py b/src/gcore/types/cdn/logs_uploader/__init__.py new file mode 100644 index 00000000..3bf54233 --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/__init__.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .config_list_params import ConfigListParams as ConfigListParams +from .policy_list_params import PolicyListParams as PolicyListParams +from .target_list_params import TargetListParams as TargetListParams +from .config_create_params import ConfigCreateParams as ConfigCreateParams +from .config_update_params import ConfigUpdateParams as ConfigUpdateParams +from .logs_uploader_config import LogsUploaderConfig as LogsUploaderConfig +from .logs_uploader_policy import LogsUploaderPolicy as LogsUploaderPolicy +from .logs_uploader_target import LogsUploaderTarget as LogsUploaderTarget +from .policy_create_params import PolicyCreateParams as PolicyCreateParams +from .policy_update_params import PolicyUpdateParams as PolicyUpdateParams +from .target_create_params import TargetCreateParams as TargetCreateParams +from .target_update_params import TargetUpdateParams as TargetUpdateParams +from .config_replace_params import ConfigReplaceParams as ConfigReplaceParams +from .policy_replace_params import PolicyReplaceParams as PolicyReplaceParams +from .target_replace_params import TargetReplaceParams as TargetReplaceParams +from .logs_uploader_config_list import LogsUploaderConfigList as LogsUploaderConfigList +from .logs_uploader_policy_list import LogsUploaderPolicyList as LogsUploaderPolicyList +from .logs_uploader_target_list import LogsUploaderTargetList as LogsUploaderTargetList +from .policy_list_fields_response import PolicyListFieldsResponse as PolicyListFieldsResponse diff --git a/src/gcore/types/cdn/logs_uploader/config_create_params.py b/src/gcore/types/cdn/logs_uploader/config_create_params.py new file mode 100644 index 00000000..40e51bdf --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/config_create_params.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["ConfigCreateParams"] + + +class ConfigCreateParams(TypedDict, total=False): + name: Required[str] + """Name of the config.""" + + policy: Required[int] + """ID of the policy that should be assigned to given config.""" + + target: Required[int] + """ID of the target to which logs should be uploaded.""" + + enabled: bool + """Enables or disables the config.""" + + for_all_resources: bool + """ + If set to true, the config will be applied to all CDN resources. If set to + false, the config will be applied to the resources specified in the `resources` + field. + """ + + resources: Iterable[int] + """List of resource IDs to which the config should be applied.""" diff --git a/src/gcore/types/cdn/logs_uploader/config_list_params.py b/src/gcore/types/cdn/logs_uploader/config_list_params.py new file mode 100644 index 00000000..8b2e42b2 --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/config_list_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import TypedDict + +__all__ = ["ConfigListParams"] + + +class ConfigListParams(TypedDict, total=False): + resource_ids: Iterable[int] + """Filter by ids of CDN resources that are assigned to given config.""" + + search: str + """Search by config name or id.""" diff --git a/src/gcore/types/cdn/logs_uploader/config_replace_params.py b/src/gcore/types/cdn/logs_uploader/config_replace_params.py new file mode 100644 index 00000000..398da0ae --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/config_replace_params.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["ConfigReplaceParams"] + + +class ConfigReplaceParams(TypedDict, total=False): + name: Required[str] + """Name of the config.""" + + policy: Required[int] + """ID of the policy that should be assigned to given config.""" + + target: Required[int] + """ID of the target to which logs should be uploaded.""" + + enabled: bool + """Enables or disables the config.""" + + for_all_resources: bool + """ + If set to true, the config will be applied to all CDN resources. If set to + false, the config will be applied to the resources specified in the `resources` + field. + """ + + resources: Iterable[int] + """List of resource IDs to which the config should be applied.""" diff --git a/src/gcore/types/cdn/logs_uploader/config_update_params.py b/src/gcore/types/cdn/logs_uploader/config_update_params.py new file mode 100644 index 00000000..d0dcd2cb --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/config_update_params.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import TypedDict + +__all__ = ["ConfigUpdateParams"] + + +class ConfigUpdateParams(TypedDict, total=False): + enabled: bool + """Enables or disables the config.""" + + for_all_resources: bool + """ + If set to true, the config will be applied to all CDN resources. If set to + false, the config will be applied to the resources specified in the `resources` + field. + """ + + name: str + """Name of the config.""" + + policy: int + """ID of the policy that should be assigned to given config.""" + + resources: Iterable[int] + """List of resource IDs to which the config should be applied.""" + + target: int + """ID of the target to which logs should be uploaded.""" diff --git a/src/gcore/types/cdn/logs_uploader/logs_uploader_config.py b/src/gcore/types/cdn/logs_uploader/logs_uploader_config.py new file mode 100644 index 00000000..25edbfe1 --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/logs_uploader_config.py @@ -0,0 +1,53 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from ...._models import BaseModel +from ..logs_uploader_validation import LogsUploaderValidation + +__all__ = ["LogsUploaderConfig", "Status"] + + +class Status(LogsUploaderValidation): + """Validation status of the logs uploader config.""" + + pass + + +class LogsUploaderConfig(BaseModel): + id: Optional[int] = None + + client_id: Optional[int] = None + """Client that owns the config.""" + + created: Optional[datetime] = None + """Time when the config was created.""" + + enabled: Optional[bool] = None + """Enables or disables the config.""" + + for_all_resources: Optional[bool] = None + """ + If set to true, the config will be applied to all CDN resources. If set to + false, the config will be applied to the resources specified in the `resources` + field. + """ + + name: Optional[str] = None + """Name of the config.""" + + policy: Optional[int] = None + """ID of the policy that should be assigned to given config.""" + + resources: Optional[List[int]] = None + """List of resource IDs to which the config should be applied.""" + + status: Optional[Status] = None + """Validation status of the logs uploader config.""" + + target: Optional[int] = None + """ID of the target to which logs should be uploaded.""" + + updated: Optional[datetime] = None + """Time when the config was updated.""" diff --git a/src/gcore/types/cdn/logs_uploader/logs_uploader_config_list.py b/src/gcore/types/cdn/logs_uploader/logs_uploader_config_list.py new file mode 100644 index 00000000..477aaf6c --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/logs_uploader_config_list.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .logs_uploader_config import LogsUploaderConfig + +__all__ = ["LogsUploaderConfigList"] + +LogsUploaderConfigList: TypeAlias = List[LogsUploaderConfig] diff --git a/src/gcore/types/cdn/logs_uploader/logs_uploader_policy.py b/src/gcore/types/cdn/logs_uploader/logs_uploader_policy.py new file mode 100644 index 00000000..b71e8375 --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/logs_uploader_policy.py @@ -0,0 +1,106 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["LogsUploaderPolicy"] + + +class LogsUploaderPolicy(BaseModel): + id: Optional[int] = None + + client_id: Optional[int] = None + """Client that owns the policy.""" + + created: Optional[datetime] = None + """Time when logs uploader policy was created.""" + + date_format: Optional[str] = None + """Date format for logs.""" + + description: Optional[str] = None + """Description of the policy.""" + + escape_special_characters: Optional[bool] = None + """ + When set to true, the service sanitizes string values by escaping characters + that may be unsafe for transport, logging, or downstream processing. + + The following categories of characters are escaped: + + - Control and non-printable characters + - Quotation marks and escape characters + - Characters outside the standard ASCII range + + The resulting output contains only printable ASCII characters. + """ + + field_delimiter: Optional[str] = None + """Field delimiter for logs.""" + + field_separator: Optional[str] = None + """Field separator for logs.""" + + fields: Optional[List[str]] = None + """List of fields to include in logs.""" + + file_name_template: Optional[str] = None + """Template for log file name.""" + + format_type: Optional[Literal["json", ""]] = None + """Format type for logs. + + Possible values: + + - **""** - empty, it means it will apply the format configurations from the + policy. + - **"json"** - output the logs as json lines. + """ + + include_empty_logs: Optional[bool] = None + """Include empty logs in the upload.""" + + include_shield_logs: Optional[bool] = None + """Include logs from origin shielding in the upload.""" + + log_sample_rate: Optional[float] = None + """Sampling rate for logs. + + A value between 0 and 1 that determines the fraction of log entries to collect. + + - **1** - collect all logs (default). + - **0.5** - collect approximately 50% of logs. + - **0** - collect no logs (effectively disables logging without removing the + policy). + """ + + name: Optional[str] = None + """Name of the policy.""" + + related_uploader_configs: Optional[List[int]] = None + """List of logs uploader configs that use this policy.""" + + retry_interval_minutes: Optional[int] = None + """Interval in minutes to retry failed uploads.""" + + rotate_interval_minutes: Optional[int] = None + """Interval in minutes to rotate logs.""" + + rotate_threshold_lines: Optional[int] = None + """Threshold in lines to rotate logs.""" + + rotate_threshold_mb: Optional[int] = None + """Threshold in MB to rotate logs.""" + + tags: Optional[Dict[str, str]] = None + """ + Tags allow for dynamic decoration of logs by adding predefined fields to the log + format. These tags serve as customizable key-value pairs that can be included in + log entries to enhance context and readability. + """ + + updated: Optional[datetime] = None + """Time when logs uploader policy was updated.""" diff --git a/src/gcore/types/cdn/logs_uploader/logs_uploader_policy_list.py b/src/gcore/types/cdn/logs_uploader/logs_uploader_policy_list.py new file mode 100644 index 00000000..75f9a44e --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/logs_uploader_policy_list.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .logs_uploader_policy import LogsUploaderPolicy + +__all__ = ["LogsUploaderPolicyList"] + +LogsUploaderPolicyList: TypeAlias = List[LogsUploaderPolicy] diff --git a/src/gcore/types/cdn/logs_uploader/logs_uploader_target.py b/src/gcore/types/cdn/logs_uploader/logs_uploader_target.py new file mode 100644 index 00000000..e5f040a9 --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/logs_uploader_target.py @@ -0,0 +1,243 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, TypeAlias + +from ...._models import BaseModel +from ..logs_uploader_validation import LogsUploaderValidation + +__all__ = [ + "LogsUploaderTarget", + "Config", + "ConfigS3GcoreConfigResponse", + "ConfigS3AmazonConfigResponse", + "ConfigUnionMember2", + "ConfigBaseFtpConfig", + "ConfigSftpConfigResponse", + "ConfigHTTPConfigResponse", + "ConfigHTTPConfigResponseAppend", + "ConfigHTTPConfigResponseAppendResponseAction", + "ConfigHTTPConfigResponseAuth", + "ConfigHTTPConfigResponseAuthConfig", + "ConfigHTTPConfigResponseRetry", + "ConfigHTTPConfigResponseRetryResponseAction", + "ConfigHTTPConfigResponseUpload", + "ConfigHTTPConfigResponseUploadResponseAction", + "Status", +] + + +class ConfigS3GcoreConfigResponse(BaseModel): + access_key_id: Optional[str] = None + + bucket_name: Optional[str] = None + + directory: Optional[str] = None + + endpoint: Optional[str] = None + + region: Optional[str] = None + + use_path_style: Optional[bool] = None + + +class ConfigS3AmazonConfigResponse(BaseModel): + access_key_id: Optional[str] = None + + bucket_name: Optional[str] = None + + directory: Optional[str] = None + + region: Optional[str] = None + + +class ConfigUnionMember2(BaseModel): + access_key_id: Optional[str] = None + + bucket_name: Optional[str] = None + + directory: Optional[str] = None + + endpoint: Optional[str] = None + + region: Optional[str] = None + + +class ConfigBaseFtpConfig(BaseModel): + directory: Optional[str] = None + + hostname: Optional[str] = None + + timeout_seconds: Optional[int] = None + + user: Optional[str] = None + + +class ConfigSftpConfigResponse(BaseModel): + hostname: str + + user: str + + directory: Optional[str] = None + + key_passphrase: Optional[str] = None + + password: Optional[str] = None + + private_key: Optional[str] = None + + timeout_seconds: Optional[int] = None + + +class ConfigHTTPConfigResponseAppendResponseAction(BaseModel): + action: Optional[Literal["drop", "retry", "append"]] = None + + description: Optional[str] = None + + match_payload: Optional[str] = None + + match_status_code: Optional[int] = None + + +class ConfigHTTPConfigResponseAppend(BaseModel): + headers: Optional[Dict[str, str]] = None + + method: Optional[Literal["POST", "PUT"]] = None + + response_actions: Optional[List[ConfigHTTPConfigResponseAppendResponseAction]] = None + + timeout_seconds: Optional[int] = None + + url: Optional[str] = None + + use_compression: Optional[bool] = None + + +class ConfigHTTPConfigResponseAuthConfig(BaseModel): + token: Optional[str] = None + + header_name: Optional[str] = None + + +class ConfigHTTPConfigResponseAuth(BaseModel): + config: Optional[ConfigHTTPConfigResponseAuthConfig] = None + + type: Optional[Literal["token"]] = None + + +class ConfigHTTPConfigResponseRetryResponseAction(BaseModel): + action: Optional[Literal["drop", "retry", "append"]] = None + + description: Optional[str] = None + + match_payload: Optional[str] = None + + match_status_code: Optional[int] = None + + +class ConfigHTTPConfigResponseRetry(BaseModel): + headers: Optional[Dict[str, str]] = None + + method: Optional[Literal["POST", "PUT"]] = None + + response_actions: Optional[List[ConfigHTTPConfigResponseRetryResponseAction]] = None + + timeout_seconds: Optional[int] = None + + url: Optional[str] = None + + use_compression: Optional[bool] = None + + +class ConfigHTTPConfigResponseUploadResponseAction(BaseModel): + action: Optional[Literal["drop", "retry", "append"]] = None + + description: Optional[str] = None + + match_payload: Optional[str] = None + + match_status_code: Optional[int] = None + + +class ConfigHTTPConfigResponseUpload(BaseModel): + headers: Optional[Dict[str, str]] = None + + method: Optional[Literal["POST", "PUT"]] = None + + response_actions: Optional[List[ConfigHTTPConfigResponseUploadResponseAction]] = None + + timeout_seconds: Optional[int] = None + + url: Optional[str] = None + + use_compression: Optional[bool] = None + + +class ConfigHTTPConfigResponse(BaseModel): + append: Optional[ConfigHTTPConfigResponseAppend] = None + + auth: Optional[ConfigHTTPConfigResponseAuth] = None + + content_type: Optional[Literal["json", "text"]] = None + + retry: Optional[ConfigHTTPConfigResponseRetry] = None + + upload: Optional[ConfigHTTPConfigResponseUpload] = None + + +Config: TypeAlias = Union[ + ConfigS3GcoreConfigResponse, + ConfigS3AmazonConfigResponse, + ConfigUnionMember2, + ConfigS3GcoreConfigResponse, + ConfigS3GcoreConfigResponse, + ConfigBaseFtpConfig, + ConfigSftpConfigResponse, + ConfigHTTPConfigResponse, +] + + +class Status(LogsUploaderValidation): + """Validation status of the logs uploader target. + + Informs if the specified target is reachable. + """ + + pass + + +class LogsUploaderTarget(BaseModel): + id: Optional[int] = None + + client_id: Optional[int] = None + """Client that owns the target.""" + + config: Optional[Config] = None + """Config for specific storage type.""" + + created: Optional[datetime] = None + """Time when logs uploader target was created.""" + + description: Optional[str] = None + """Description of the target.""" + + name: Optional[str] = None + """Name of the target.""" + + related_uploader_configs: Optional[List[int]] = None + """List of logs uploader configs that use this target.""" + + status: Optional[Status] = None + """Validation status of the logs uploader target. + + Informs if the specified target is reachable. + """ + + storage_type: Optional[Literal["s3_gcore", "s3_amazon", "s3_oss", "s3_other", "s3_v1", "ftp", "sftp", "http"]] = ( + None + ) + """Type of storage for logs.""" + + updated: Optional[datetime] = None + """Time when logs uploader target was updated.""" diff --git a/src/gcore/types/cdn/logs_uploader/logs_uploader_target_list.py b/src/gcore/types/cdn/logs_uploader/logs_uploader_target_list.py new file mode 100644 index 00000000..f3df6d6b --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/logs_uploader_target_list.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .logs_uploader_target import LogsUploaderTarget + +__all__ = ["LogsUploaderTargetList"] + +LogsUploaderTargetList: TypeAlias = List[LogsUploaderTarget] diff --git a/src/gcore/types/cdn/logs_uploader/policy_create_params.py b/src/gcore/types/cdn/logs_uploader/policy_create_params.py new file mode 100644 index 00000000..4d25b99a --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/policy_create_params.py @@ -0,0 +1,93 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Literal, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["PolicyCreateParams"] + + +class PolicyCreateParams(TypedDict, total=False): + date_format: str + """Date format for logs.""" + + description: str + """Description of the policy.""" + + escape_special_characters: bool + """ + When set to true, the service sanitizes string values by escaping characters + that may be unsafe for transport, logging, or downstream processing. + + The following categories of characters are escaped: + + - Control and non-printable characters + - Quotation marks and escape characters + - Characters outside the standard ASCII range + + The resulting output contains only printable ASCII characters. + """ + + field_delimiter: str + """Field delimiter for logs.""" + + field_separator: str + """Field separator for logs.""" + + fields: SequenceNotStr[str] + """List of fields to include in logs.""" + + file_name_template: str + """Template for log file name.""" + + format_type: Literal["json", ""] + """Format type for logs. + + Possible values: + + - **""** - empty, it means it will apply the format configurations from the + policy. + - **"json"** - output the logs as json lines. + """ + + include_empty_logs: bool + """Include empty logs in the upload.""" + + include_shield_logs: bool + """Include logs from origin shielding in the upload.""" + + log_sample_rate: float + """Sampling rate for logs. + + A value between 0 and 1 that determines the fraction of log entries to collect. + + - **1** - collect all logs (default). + - **0.5** - collect approximately 50% of logs. + - **0** - collect no logs (effectively disables logging without removing the + policy). + """ + + name: str + """Name of the policy.""" + + retry_interval_minutes: int + """Interval in minutes to retry failed uploads.""" + + rotate_interval_minutes: int + """Interval in minutes to rotate logs.""" + + rotate_threshold_lines: int + """Threshold in lines to rotate logs.""" + + rotate_threshold_mb: Optional[int] + """Threshold in MB to rotate logs.""" + + tags: Dict[str, str] + """ + Tags allow for dynamic decoration of logs by adding predefined fields to the log + format. These tags serve as customizable key-value pairs that can be included in + log entries to enhance context and readability. + """ diff --git a/src/gcore/types/cdn/logs_uploader/policy_list_fields_response.py b/src/gcore/types/cdn/logs_uploader/policy_list_fields_response.py new file mode 100644 index 00000000..fcfbca93 --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/policy_list_fields_response.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +__all__ = ["PolicyListFieldsResponse"] + +PolicyListFieldsResponse: TypeAlias = List[str] diff --git a/src/gcore/types/cdn/logs_uploader/policy_list_params.py b/src/gcore/types/cdn/logs_uploader/policy_list_params.py new file mode 100644 index 00000000..4b2a2b4a --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/policy_list_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import TypedDict + +__all__ = ["PolicyListParams"] + + +class PolicyListParams(TypedDict, total=False): + config_ids: Iterable[int] + """Filter by ids of related logs uploader configs that use given policy.""" + + search: str + """Search by policy name or id.""" diff --git a/src/gcore/types/cdn/logs_uploader/policy_replace_params.py b/src/gcore/types/cdn/logs_uploader/policy_replace_params.py new file mode 100644 index 00000000..1087c1f7 --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/policy_replace_params.py @@ -0,0 +1,93 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Literal, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["PolicyReplaceParams"] + + +class PolicyReplaceParams(TypedDict, total=False): + date_format: str + """Date format for logs.""" + + description: str + """Description of the policy.""" + + escape_special_characters: bool + """ + When set to true, the service sanitizes string values by escaping characters + that may be unsafe for transport, logging, or downstream processing. + + The following categories of characters are escaped: + + - Control and non-printable characters + - Quotation marks and escape characters + - Characters outside the standard ASCII range + + The resulting output contains only printable ASCII characters. + """ + + field_delimiter: str + """Field delimiter for logs.""" + + field_separator: str + """Field separator for logs.""" + + fields: SequenceNotStr[str] + """List of fields to include in logs.""" + + file_name_template: str + """Template for log file name.""" + + format_type: Literal["json", ""] + """Format type for logs. + + Possible values: + + - **""** - empty, it means it will apply the format configurations from the + policy. + - **"json"** - output the logs as json lines. + """ + + include_empty_logs: bool + """Include empty logs in the upload.""" + + include_shield_logs: bool + """Include logs from origin shielding in the upload.""" + + log_sample_rate: float + """Sampling rate for logs. + + A value between 0 and 1 that determines the fraction of log entries to collect. + + - **1** - collect all logs (default). + - **0.5** - collect approximately 50% of logs. + - **0** - collect no logs (effectively disables logging without removing the + policy). + """ + + name: str + """Name of the policy.""" + + retry_interval_minutes: int + """Interval in minutes to retry failed uploads.""" + + rotate_interval_minutes: int + """Interval in minutes to rotate logs.""" + + rotate_threshold_lines: int + """Threshold in lines to rotate logs.""" + + rotate_threshold_mb: Optional[int] + """Threshold in MB to rotate logs.""" + + tags: Dict[str, str] + """ + Tags allow for dynamic decoration of logs by adding predefined fields to the log + format. These tags serve as customizable key-value pairs that can be included in + log entries to enhance context and readability. + """ diff --git a/src/gcore/types/cdn/logs_uploader/policy_update_params.py b/src/gcore/types/cdn/logs_uploader/policy_update_params.py new file mode 100644 index 00000000..43ad9e99 --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/policy_update_params.py @@ -0,0 +1,93 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Literal, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["PolicyUpdateParams"] + + +class PolicyUpdateParams(TypedDict, total=False): + date_format: str + """Date format for logs.""" + + description: str + """Description of the policy.""" + + escape_special_characters: bool + """ + When set to true, the service sanitizes string values by escaping characters + that may be unsafe for transport, logging, or downstream processing. + + The following categories of characters are escaped: + + - Control and non-printable characters + - Quotation marks and escape characters + - Characters outside the standard ASCII range + + The resulting output contains only printable ASCII characters. + """ + + field_delimiter: str + """Field delimiter for logs.""" + + field_separator: str + """Field separator for logs.""" + + fields: SequenceNotStr[str] + """List of fields to include in logs.""" + + file_name_template: str + """Template for log file name.""" + + format_type: Literal["json", ""] + """Format type for logs. + + Possible values: + + - **""** - empty, it means it will apply the format configurations from the + policy. + - **"json"** - output the logs as json lines. + """ + + include_empty_logs: bool + """Include empty logs in the upload.""" + + include_shield_logs: bool + """Include logs from origin shielding in the upload.""" + + log_sample_rate: float + """Sampling rate for logs. + + A value between 0 and 1 that determines the fraction of log entries to collect. + + - **1** - collect all logs (default). + - **0.5** - collect approximately 50% of logs. + - **0** - collect no logs (effectively disables logging without removing the + policy). + """ + + name: str + """Name of the policy.""" + + retry_interval_minutes: int + """Interval in minutes to retry failed uploads.""" + + rotate_interval_minutes: int + """Interval in minutes to rotate logs.""" + + rotate_threshold_lines: int + """Threshold in lines to rotate logs.""" + + rotate_threshold_mb: Optional[int] + """Threshold in MB to rotate logs.""" + + tags: Dict[str, str] + """ + Tags allow for dynamic decoration of logs by adding predefined fields to the log + format. These tags serve as customizable key-value pairs that can be included in + log entries to enhance context and readability. + """ diff --git a/src/gcore/types/cdn/logs_uploader/target_create_params.py b/src/gcore/types/cdn/logs_uploader/target_create_params.py new file mode 100644 index 00000000..d48e6374 --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/target_create_params.py @@ -0,0 +1,251 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "TargetCreateParams", + "Config", + "ConfigS3GcoreConfig", + "ConfigS3AmazonConfig", + "ConfigS3OssConfig", + "ConfigS3OtherConfig", + "ConfigS3V1Config", + "ConfigFtpConfig", + "ConfigSftpConfig", + "ConfigHTTPConfig", + "ConfigHTTPConfigUpload", + "ConfigHTTPConfigUploadResponseAction", + "ConfigHTTPConfigAppend", + "ConfigHTTPConfigAppendResponseAction", + "ConfigHTTPConfigAuth", + "ConfigHTTPConfigAuthConfig", + "ConfigHTTPConfigRetry", + "ConfigHTTPConfigRetryResponseAction", +] + + +class TargetCreateParams(TypedDict, total=False): + config: Required[Config] + """Config for specific storage type.""" + + storage_type: Required[Literal["s3_gcore", "s3_amazon", "s3_oss", "s3_other", "s3_v1", "ftp", "sftp", "http"]] + """Type of storage for logs.""" + + description: str + """Description of the target.""" + + name: str + """Name of the target.""" + + +class ConfigS3GcoreConfig(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + endpoint: Required[str] + + region: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + use_path_style: bool + + +class ConfigS3AmazonConfig(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + region: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + +class ConfigS3OssConfig(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + endpoint: Optional[str] + + region: Optional[str] + + +class ConfigS3OtherConfig(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + endpoint: Required[str] + + region: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + use_path_style: bool + + +class ConfigS3V1Config(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + endpoint: Required[str] + + region: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + use_path_style: bool + + +class ConfigFtpConfig(TypedDict, total=False): + hostname: Required[str] + + password: Required[str] + + user: Required[str] + + directory: Optional[str] + + timeout_seconds: int + + +class ConfigSftpConfig(TypedDict, total=False): + hostname: Required[str] + + user: Required[str] + + directory: Optional[str] + + key_passphrase: Optional[str] + + password: Optional[str] + + private_key: Optional[str] + + timeout_seconds: int + + +class ConfigHTTPConfigUploadResponseAction(TypedDict, total=False): + action: Required[Literal["drop", "retry", "append"]] + + description: str + + match_payload: str + + match_status_code: int + + +class ConfigHTTPConfigUpload(TypedDict, total=False): + url: Required[str] + + headers: Dict[str, str] + + method: Literal["POST", "PUT"] + + response_actions: Iterable[ConfigHTTPConfigUploadResponseAction] + + timeout_seconds: int + + use_compression: bool + + +class ConfigHTTPConfigAppendResponseAction(TypedDict, total=False): + action: Required[Literal["drop", "retry", "append"]] + + description: str + + match_payload: str + + match_status_code: int + + +class ConfigHTTPConfigAppend(TypedDict, total=False): + url: Required[str] + + headers: Dict[str, str] + + method: Literal["POST", "PUT"] + + response_actions: Iterable[ConfigHTTPConfigAppendResponseAction] + + timeout_seconds: int + + use_compression: bool + + +class ConfigHTTPConfigAuthConfig(TypedDict, total=False): + token: Required[str] + + header_name: Required[str] + + +class ConfigHTTPConfigAuth(TypedDict, total=False): + config: Required[ConfigHTTPConfigAuthConfig] + + type: Required[Literal["token"]] + + +class ConfigHTTPConfigRetryResponseAction(TypedDict, total=False): + action: Required[Literal["drop", "retry", "append"]] + + description: str + + match_payload: str + + match_status_code: int + + +class ConfigHTTPConfigRetry(TypedDict, total=False): + url: Required[str] + + headers: Dict[str, str] + + method: Literal["POST", "PUT"] + + response_actions: Iterable[ConfigHTTPConfigRetryResponseAction] + + timeout_seconds: int + + use_compression: bool + + +class ConfigHTTPConfig(TypedDict, total=False): + upload: Required[ConfigHTTPConfigUpload] + + append: ConfigHTTPConfigAppend + + auth: ConfigHTTPConfigAuth + + content_type: Literal["json", "text"] + + retry: ConfigHTTPConfigRetry + + +Config: TypeAlias = Union[ + ConfigS3GcoreConfig, + ConfigS3AmazonConfig, + ConfigS3OssConfig, + ConfigS3OtherConfig, + ConfigS3V1Config, + ConfigFtpConfig, + ConfigSftpConfig, + ConfigHTTPConfig, +] diff --git a/src/gcore/types/cdn/logs_uploader/target_list_params.py b/src/gcore/types/cdn/logs_uploader/target_list_params.py new file mode 100644 index 00000000..aed247de --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/target_list_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import TypedDict + +__all__ = ["TargetListParams"] + + +class TargetListParams(TypedDict, total=False): + config_ids: Iterable[int] + """Filter by ids of related logs uploader configs that use given target.""" + + search: str + """Search by target name or id.""" diff --git a/src/gcore/types/cdn/logs_uploader/target_replace_params.py b/src/gcore/types/cdn/logs_uploader/target_replace_params.py new file mode 100644 index 00000000..2a97435c --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/target_replace_params.py @@ -0,0 +1,251 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "TargetReplaceParams", + "Config", + "ConfigS3GcoreConfig", + "ConfigS3AmazonConfig", + "ConfigS3OssConfig", + "ConfigS3OtherConfig", + "ConfigS3V1Config", + "ConfigFtpConfig", + "ConfigSftpConfig", + "ConfigHTTPConfig", + "ConfigHTTPConfigUpload", + "ConfigHTTPConfigUploadResponseAction", + "ConfigHTTPConfigAppend", + "ConfigHTTPConfigAppendResponseAction", + "ConfigHTTPConfigAuth", + "ConfigHTTPConfigAuthConfig", + "ConfigHTTPConfigRetry", + "ConfigHTTPConfigRetryResponseAction", +] + + +class TargetReplaceParams(TypedDict, total=False): + config: Required[Config] + """Config for specific storage type.""" + + storage_type: Required[Literal["s3_gcore", "s3_amazon", "s3_oss", "s3_other", "s3_v1", "ftp", "sftp", "http"]] + """Type of storage for logs.""" + + description: str + """Description of the target.""" + + name: str + """Name of the target.""" + + +class ConfigS3GcoreConfig(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + endpoint: Required[str] + + region: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + use_path_style: bool + + +class ConfigS3AmazonConfig(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + region: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + +class ConfigS3OssConfig(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + endpoint: Optional[str] + + region: Optional[str] + + +class ConfigS3OtherConfig(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + endpoint: Required[str] + + region: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + use_path_style: bool + + +class ConfigS3V1Config(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + endpoint: Required[str] + + region: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + use_path_style: bool + + +class ConfigFtpConfig(TypedDict, total=False): + hostname: Required[str] + + password: Required[str] + + user: Required[str] + + directory: Optional[str] + + timeout_seconds: int + + +class ConfigSftpConfig(TypedDict, total=False): + hostname: Required[str] + + user: Required[str] + + directory: Optional[str] + + key_passphrase: Optional[str] + + password: Optional[str] + + private_key: Optional[str] + + timeout_seconds: int + + +class ConfigHTTPConfigUploadResponseAction(TypedDict, total=False): + action: Required[Literal["drop", "retry", "append"]] + + description: str + + match_payload: str + + match_status_code: int + + +class ConfigHTTPConfigUpload(TypedDict, total=False): + url: Required[str] + + headers: Dict[str, str] + + method: Literal["POST", "PUT"] + + response_actions: Iterable[ConfigHTTPConfigUploadResponseAction] + + timeout_seconds: int + + use_compression: bool + + +class ConfigHTTPConfigAppendResponseAction(TypedDict, total=False): + action: Required[Literal["drop", "retry", "append"]] + + description: str + + match_payload: str + + match_status_code: int + + +class ConfigHTTPConfigAppend(TypedDict, total=False): + url: Required[str] + + headers: Dict[str, str] + + method: Literal["POST", "PUT"] + + response_actions: Iterable[ConfigHTTPConfigAppendResponseAction] + + timeout_seconds: int + + use_compression: bool + + +class ConfigHTTPConfigAuthConfig(TypedDict, total=False): + token: Required[str] + + header_name: Required[str] + + +class ConfigHTTPConfigAuth(TypedDict, total=False): + config: Required[ConfigHTTPConfigAuthConfig] + + type: Required[Literal["token"]] + + +class ConfigHTTPConfigRetryResponseAction(TypedDict, total=False): + action: Required[Literal["drop", "retry", "append"]] + + description: str + + match_payload: str + + match_status_code: int + + +class ConfigHTTPConfigRetry(TypedDict, total=False): + url: Required[str] + + headers: Dict[str, str] + + method: Literal["POST", "PUT"] + + response_actions: Iterable[ConfigHTTPConfigRetryResponseAction] + + timeout_seconds: int + + use_compression: bool + + +class ConfigHTTPConfig(TypedDict, total=False): + upload: Required[ConfigHTTPConfigUpload] + + append: ConfigHTTPConfigAppend + + auth: ConfigHTTPConfigAuth + + content_type: Literal["json", "text"] + + retry: ConfigHTTPConfigRetry + + +Config: TypeAlias = Union[ + ConfigS3GcoreConfig, + ConfigS3AmazonConfig, + ConfigS3OssConfig, + ConfigS3OtherConfig, + ConfigS3V1Config, + ConfigFtpConfig, + ConfigSftpConfig, + ConfigHTTPConfig, +] diff --git a/src/gcore/types/cdn/logs_uploader/target_update_params.py b/src/gcore/types/cdn/logs_uploader/target_update_params.py new file mode 100644 index 00000000..34730db0 --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader/target_update_params.py @@ -0,0 +1,251 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "TargetUpdateParams", + "Config", + "ConfigS3GcoreConfig", + "ConfigS3AmazonConfig", + "ConfigS3OssConfig", + "ConfigS3OtherConfig", + "ConfigS3V1Config", + "ConfigFtpConfig", + "ConfigSftpConfig", + "ConfigHTTPConfig", + "ConfigHTTPConfigUpload", + "ConfigHTTPConfigUploadResponseAction", + "ConfigHTTPConfigAppend", + "ConfigHTTPConfigAppendResponseAction", + "ConfigHTTPConfigAuth", + "ConfigHTTPConfigAuthConfig", + "ConfigHTTPConfigRetry", + "ConfigHTTPConfigRetryResponseAction", +] + + +class TargetUpdateParams(TypedDict, total=False): + config: Config + """Config for specific storage type.""" + + description: str + """Description of the target.""" + + name: str + """Name of the target.""" + + storage_type: Literal["s3_gcore", "s3_amazon", "s3_oss", "s3_other", "s3_v1", "ftp", "sftp", "http"] + """Type of storage for logs.""" + + +class ConfigS3GcoreConfig(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + endpoint: Required[str] + + region: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + use_path_style: bool + + +class ConfigS3AmazonConfig(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + region: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + +class ConfigS3OssConfig(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + endpoint: Optional[str] + + region: Optional[str] + + +class ConfigS3OtherConfig(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + endpoint: Required[str] + + region: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + use_path_style: bool + + +class ConfigS3V1Config(TypedDict, total=False): + access_key_id: Required[str] + + bucket_name: Required[str] + + endpoint: Required[str] + + region: Required[str] + + secret_access_key: Required[str] + + directory: Optional[str] + + use_path_style: bool + + +class ConfigFtpConfig(TypedDict, total=False): + hostname: Required[str] + + password: Required[str] + + user: Required[str] + + directory: Optional[str] + + timeout_seconds: int + + +class ConfigSftpConfig(TypedDict, total=False): + hostname: Required[str] + + user: Required[str] + + directory: Optional[str] + + key_passphrase: Optional[str] + + password: Optional[str] + + private_key: Optional[str] + + timeout_seconds: int + + +class ConfigHTTPConfigUploadResponseAction(TypedDict, total=False): + action: Required[Literal["drop", "retry", "append"]] + + description: str + + match_payload: str + + match_status_code: int + + +class ConfigHTTPConfigUpload(TypedDict, total=False): + url: Required[str] + + headers: Dict[str, str] + + method: Literal["POST", "PUT"] + + response_actions: Iterable[ConfigHTTPConfigUploadResponseAction] + + timeout_seconds: int + + use_compression: bool + + +class ConfigHTTPConfigAppendResponseAction(TypedDict, total=False): + action: Required[Literal["drop", "retry", "append"]] + + description: str + + match_payload: str + + match_status_code: int + + +class ConfigHTTPConfigAppend(TypedDict, total=False): + url: Required[str] + + headers: Dict[str, str] + + method: Literal["POST", "PUT"] + + response_actions: Iterable[ConfigHTTPConfigAppendResponseAction] + + timeout_seconds: int + + use_compression: bool + + +class ConfigHTTPConfigAuthConfig(TypedDict, total=False): + token: Required[str] + + header_name: Required[str] + + +class ConfigHTTPConfigAuth(TypedDict, total=False): + config: Required[ConfigHTTPConfigAuthConfig] + + type: Required[Literal["token"]] + + +class ConfigHTTPConfigRetryResponseAction(TypedDict, total=False): + action: Required[Literal["drop", "retry", "append"]] + + description: str + + match_payload: str + + match_status_code: int + + +class ConfigHTTPConfigRetry(TypedDict, total=False): + url: Required[str] + + headers: Dict[str, str] + + method: Literal["POST", "PUT"] + + response_actions: Iterable[ConfigHTTPConfigRetryResponseAction] + + timeout_seconds: int + + use_compression: bool + + +class ConfigHTTPConfig(TypedDict, total=False): + upload: Required[ConfigHTTPConfigUpload] + + append: ConfigHTTPConfigAppend + + auth: ConfigHTTPConfigAuth + + content_type: Literal["json", "text"] + + retry: ConfigHTTPConfigRetry + + +Config: TypeAlias = Union[ + ConfigS3GcoreConfig, + ConfigS3AmazonConfig, + ConfigS3OssConfig, + ConfigS3OtherConfig, + ConfigS3V1Config, + ConfigFtpConfig, + ConfigSftpConfig, + ConfigHTTPConfig, +] diff --git a/src/gcore/types/cdn/logs_uploader_validation.py b/src/gcore/types/cdn/logs_uploader_validation.py new file mode 100644 index 00000000..6f24857d --- /dev/null +++ b/src/gcore/types/cdn/logs_uploader_validation.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["LogsUploaderValidation"] + + +class LogsUploaderValidation(BaseModel): + code: Optional[int] = None + """Error code indicating the type of validation error.""" + + details: Optional[str] = None + """Error message if the validation failed.""" + + status: Optional[Literal["in_progress", "successful", "failed"]] = None + """Status of the validation.""" + + updated: Optional[datetime] = None + """Time when the validation status was updated.""" diff --git a/src/gcore/types/cdn/metric_list_params.py b/src/gcore/types/cdn/metric_list_params.py new file mode 100644 index 00000000..42aa48e4 --- /dev/null +++ b/src/gcore/types/cdn/metric_list_params.py @@ -0,0 +1,168 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Required, Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = ["MetricListParams", "FilterBy"] + + +class MetricListParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Beginning period to fetch metrics (ISO 8601/RFC 3339 format, UTC.) + + Examples: + + - 2021-06-14T00:00:00Z + - 2021-06-14T00:00:00.000Z + + The total number of points, which is determined as the difference between "from" + and "to" divided by "granularity", cannot exceed 1440. Exception: "speed" + metrics are limited to 72 points. + """ + + metrics: Required[SequenceNotStr[str]] + """Possible values: + + - **`edge_bandwidth`** - Bandwidth from client to CDN (bit/s.) + - **`edge_requests`** - Number of requests per interval (requests/s.) + - **`edge_requests_total`** - Total number of requests per interval. + - **`edge_status_1xx`** - Number of 1xx status codes from edge. + - **`edge_status_200`** - Number of 200 status codes from edge. + - **`edge_status_204`** - Number of 204 status codes from edge. + - **`edge_status_206`** - Number of 206 status codes from edge. + - **`edge_status_2xx`** - Number of 2xx status codes from edge. + - **`edge_status_301`** - Number of 301 status codes from edge. + - **`edge_status_302`** - Number of 302 status codes from edge. + - **`edge_status_304`** - Number of 304 status codes from edge. + - **`edge_status_3xx`** - Number of 3xx status codes from edge. + - **`edge_status_400`** - Number of 400 status codes from edge. + - **`edge_status_401`** - Number of 401 status codes from edge. + - **`edge_status_403`** - Number of 403 status codes from edge. + - **`edge_status_404`** - Number of 404 status codes from edge. + - **`edge_status_416`** - Number of 416 status codes from edge. + - **`edge_status_429`** - Number of 429 status codes from edge. + - **`edge_status_4xx`** - Number of 4xx status codes from edge. + - **`edge_status_500`** - Number of 500 status codes from edge. + - **`edge_status_501`** - Number of 501 status codes from edge. + - **`edge_status_502`** - Number of 502 status codes from edge. + - **`edge_status_503`** - Number of 503 status codes from edge. + - **`edge_status_504`** - Number of 504 status codes from edge. + - **`edge_status_505`** - Number of 505 status codes from edge. + - **`edge_status_5xx`** - Number of 5xx status codes from edge. + - **`edge_hit_ratio`** - Percent of cache hits (0.0 - 1.0). + - **`edge_hit_bytes`** - Number of bytes sent back when cache hits. + - **`origin_bandwidth`** - Bandwidth from CDN to Origin (bit/s.) + - **`origin_requests`** - Number of requests per interval (requests/s.) + - **`origin_status_1xx`** - Number of 1xx status from origin. + - **`origin_status_200`** - Number of 200 status from origin. + - **`origin_status_204`** - Number of 204 status from origin. + - **`origin_status_206`** - Number of 206 status from origin. + - **`origin_status_2xx`** - Number of 2xx status from origin. + - **`origin_status_301`** - Number of 301 status from origin. + - **`origin_status_302`** - Number of 302 status from origin. + - **`origin_status_304`** - Number of 304 status from origin. + - **`origin_status_3xx`** - Number of 3xx status from origin. + - **`origin_status_400`** - Number of 400 status from origin. + - **`origin_status_401`** - Number of 401 status from origin. + - **`origin_status_403`** - Number of 403 status from origin. + - **`origin_status_404`** - Number of 404 status from origin. + - **`origin_status_416`** - Number of 416 status from origin. + - **`origin_status_429`** - Number of 426 status from origin. + - **`origin_status_4xx`** - Number of 4xx status from origin. + - **`origin_status_500`** - Number of 500 status from origin. + - **`origin_status_501`** - Number of 501 status from origin. + - **`origin_status_502`** - Number of 502 status from origin. + - **`origin_status_503`** - Number of 503 status from origin. + - **`origin_status_504`** - Number of 504 status from origin. + - **`origin_status_505`** - Number of 505 status from origin. + - **`origin_status_5xx`** - Number of 5xx status from origin. + - **`edge_download_speed`** - Download speed from edge in KB/s (includes only + requests that status was in the range [200, 300].) + - **`origin_download_speed`** - Download speed from origin in KB/s (includes + only requests that status was in the range [200, 300].) + """ + + to: Required[str] + """Specifies ending period to fetch metrics (ISO 8601/RFC 3339 format, UTC) + + Examples: + + - 2021-06-15T00:00:00Z + - 2021-06-15T00:00:00.000Z + + The total number of points, which is determined as the difference between "from" + and "to" divided by "granularity", cannot exceed 1440. Exception: "speed" + metrics are limited to 72 points. + """ + + filter_by: Iterable[FilterBy] + """Each item represents one filter statement.""" + + granularity: str + """Duration of the time blocks into which the data is divided. + + The value must correspond to the ISO 8601 period format. + + Examples: + + - P1D + - PT5M + + Notes: + + - The total number of points, which is determined as the difference between + "from" and "to" divided by "granularity", cannot exceed 1440. Exception: + "speed" metrics are limited to 72 points. + - For "speed" metrics the value must be a multiple of 5. + """ + + group_by: SequenceNotStr[str] + """Output data grouping. + + Possible values: + + - **resource** - Data is grouped by CDN resource. + - **cname** - Data is grouped by common names. + - **region** – Data is grouped by regions (continents.) Available for "speed" + metrics only. + - **isp** - Data is grouped by ISP names. Available for "speed" metrics only. + """ + + +class FilterBy(TypedDict, total=False): + field: Required[str] + """Defines the parameters by that data can be filtered. + + Possible values: + + - **resource** - Data is filtered by CDN resource ID. + - **cname** - Data is filtered by common name. + - **region** - Data is filtered by region (continent.) Available for "speed" + metrics only. + - **isp** - Data is filtered by ISP name. Available for "speed" metrics only. + """ + + op: Required[str] + """Comparison operator to be applied. + + Possible values: + + - **in** - 'IN' operator. + - **`not_in`** - 'NOT IN' operator. + - **gt** - '>' operator. + - **gte** - '>=' operator. + - **lt** - '<' operator. + - **lte** - '<=' operator. + - **eq** - '==' operator. + - **ne** - '!=' operator. + - **like** - 'LIKE' operator. + - **`not_like`** - 'NOT LIKE' operator. + """ + + values: Required[SequenceNotStr[Union[float, str]]] + """Contains one or more values to be compared against.""" diff --git a/src/gcore/types/cdn/network_capacity.py b/src/gcore/types/cdn/network_capacity.py new file mode 100644 index 00000000..8d76c0c5 --- /dev/null +++ b/src/gcore/types/cdn/network_capacity.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["NetworkCapacity", "NetworkCapacityItem"] + + +class NetworkCapacityItem(BaseModel): + capacity: Optional[float] = None + """Network capacity in Gbit/s.""" + + country: Optional[str] = None + """Country name.""" + + country_code: Optional[str] = None + """ISO country code.""" + + +NetworkCapacity: TypeAlias = List[NetworkCapacityItem] diff --git a/src/gcore/types/cdn/origin_group_create_params.py b/src/gcore/types/cdn/origin_group_create_params.py new file mode 100644 index 00000000..2c77824a --- /dev/null +++ b/src/gcore/types/cdn/origin_group_create_params.py @@ -0,0 +1,186 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Required, TypeAlias, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["OriginGroupCreateParams", "NoneAuth", "NoneAuthSource", "AwsSignatureV4", "AwsSignatureV4Auth"] + + +class NoneAuth(TypedDict, total=False): + name: Required[str] + """Origin group name.""" + + sources: Required[Iterable[NoneAuthSource]] + """List of origin sources in the origin group.""" + + auth_type: str + """Origin authentication type. + + Possible values: + + - **none** - Used for public origins. + - **awsSignatureV4** - Used for S3 storage. + """ + + proxy_next_upstream: SequenceNotStr[str] + """Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + """ + + use_next: bool + """ + Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class NoneAuthSource(TypedDict, total=False): + backup: bool + """ + Defines whether the origin is a backup, meaning that it will not be used until + one of active origins become unavailable. + + Possible values: + + - **true** - Origin is a backup. + - **false** - Origin is not a backup. + """ + + enabled: bool + """Enables or disables an origin source in the origin group. + + Possible values: + + - **true** - Origin is enabled and the CDN uses it to pull content. + - **false** - Origin is disabled and the CDN does not use it to pull content. + + Origin group must contain at least one enabled origin. + """ + + source: str + """IP address or domain name of the origin and the port, if custom port is used.""" + + +class AwsSignatureV4(TypedDict, total=False): + auth: Required[AwsSignatureV4Auth] + """Credentials to access the private bucket.""" + + auth_type: Required[str] + """Authentication type. + + **awsSignatureV4** value is used for S3 storage. + """ + + name: Required[str] + """Origin group name.""" + + proxy_next_upstream: SequenceNotStr[str] + """Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + """ + + use_next: bool + """ + Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class AwsSignatureV4Auth(TypedDict, total=False): + """Credentials to access the private bucket.""" + + s3_access_key_id: Required[str] + """Access key ID for the S3 account. + + Restrictions: + + - Latin letters (A-Z, a-z), numbers (0-9), colon, dash, and underscore. + - From 3 to 512 characters. + """ + + s3_bucket_name: Required[str] + """S3 bucket name. + + Restrictions: + + - Maximum 128 characters. + """ + + s3_secret_access_key: Required[str] + """Secret access key for the S3 account. + + Restrictions: + + - Latin letters (A-Z, a-z), numbers (0-9), pluses, slashes, dashes, colons and + underscores. + - If "s3_type": amazon, length should be 40 characters. + - If "s3_type": other, length should be from 16 to 255 characters. + """ + + s3_type: Required[str] + """Storage type compatible with S3. + + Possible values: + + - **amazon** – AWS S3 storage. + - **other** – Other (not AWS) S3 compatible storage. + """ + + s3_region: str + """S3 storage region. + + The parameter is required, if "s3_type": amazon. + """ + + s3_storage_hostname: str + """S3 storage hostname. + + The parameter is required, if "s3_type": other. + """ + + +OriginGroupCreateParams: TypeAlias = Union[NoneAuth, AwsSignatureV4] diff --git a/src/gcore/types/cdn/origin_group_list_params.py b/src/gcore/types/cdn/origin_group_list_params.py new file mode 100644 index 00000000..9a19eea1 --- /dev/null +++ b/src/gcore/types/cdn/origin_group_list_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["OriginGroupListParams"] + + +class OriginGroupListParams(TypedDict, total=False): + has_related_resources: bool + """Defines whether the origin group has related CDN resources. + + Possible values: + + - **true** – Origin group has related CDN resources. + - **false** – Origin group does not have related CDN resources. + """ + + name: str + """Origin group name.""" + + sources: str + """Origin sources (IP addresses or domains) in the origin group.""" diff --git a/src/gcore/types/cdn/origin_group_replace_params.py b/src/gcore/types/cdn/origin_group_replace_params.py new file mode 100644 index 00000000..42086867 --- /dev/null +++ b/src/gcore/types/cdn/origin_group_replace_params.py @@ -0,0 +1,192 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Required, TypeAlias, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["OriginGroupReplaceParams", "NoneAuth", "NoneAuthSource", "AwsSignatureV4", "AwsSignatureV4Auth"] + + +class NoneAuth(TypedDict, total=False): + auth_type: Required[str] + """Origin authentication type. + + Possible values: + + - **none** - Used for public origins. + - **awsSignatureV4** - Used for S3 storage. + """ + + name: Required[str] + """Origin group name.""" + + path: Required[str] + """Parameter is **deprecated**.""" + + sources: Required[Iterable[NoneAuthSource]] + """List of origin sources in the origin group.""" + + use_next: Required[bool] + """ + Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + proxy_next_upstream: SequenceNotStr[str] + """Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + """ + + +class NoneAuthSource(TypedDict, total=False): + backup: bool + """ + Defines whether the origin is a backup, meaning that it will not be used until + one of active origins become unavailable. + + Possible values: + + - **true** - Origin is a backup. + - **false** - Origin is not a backup. + """ + + enabled: bool + """Enables or disables an origin source in the origin group. + + Possible values: + + - **true** - Origin is enabled and the CDN uses it to pull content. + - **false** - Origin is disabled and the CDN does not use it to pull content. + + Origin group must contain at least one enabled origin. + """ + + source: str + """IP address or domain name of the origin and the port, if custom port is used.""" + + +class AwsSignatureV4(TypedDict, total=False): + auth: Required[AwsSignatureV4Auth] + """Credentials to access the private bucket.""" + + auth_type: Required[str] + """Authentication type. + + **awsSignatureV4** value is used for S3 storage. + """ + + name: Required[str] + """Origin group name.""" + + path: Required[str] + """Parameter is **deprecated**.""" + + use_next: Required[bool] + """ + Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + proxy_next_upstream: SequenceNotStr[str] + """Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + """ + + +class AwsSignatureV4Auth(TypedDict, total=False): + """Credentials to access the private bucket.""" + + s3_access_key_id: Required[str] + """Access key ID for the S3 account. + + Restrictions: + + - Latin letters (A-Z, a-z), numbers (0-9), colon, dash, and underscore. + - From 3 to 512 characters. + """ + + s3_bucket_name: Required[str] + """S3 bucket name. + + Restrictions: + + - Maximum 128 characters. + """ + + s3_secret_access_key: Required[str] + """Secret access key for the S3 account. + + Restrictions: + + - Latin letters (A-Z, a-z), numbers (0-9), pluses, slashes, dashes, colons and + underscores. + - If "s3_type": amazon, length should be 40 characters. + - If "s3_type": other, length should be from 16 to 255 characters. + """ + + s3_type: Required[str] + """Storage type compatible with S3. + + Possible values: + + - **amazon** – AWS S3 storage. + - **other** – Other (not AWS) S3 compatible storage. + """ + + s3_region: str + """S3 storage region. + + The parameter is required, if "s3_type": amazon. + """ + + s3_storage_hostname: str + """S3 storage hostname. + + The parameter is required, if "s3_type": other. + """ + + +OriginGroupReplaceParams: TypeAlias = Union[NoneAuth, AwsSignatureV4] diff --git a/src/gcore/types/cdn/origin_group_update_params.py b/src/gcore/types/cdn/origin_group_update_params.py new file mode 100644 index 00000000..1b4efd18 --- /dev/null +++ b/src/gcore/types/cdn/origin_group_update_params.py @@ -0,0 +1,192 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Required, TypeAlias, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["OriginGroupUpdateParams", "NoneAuth", "NoneAuthSource", "AwsSignatureV4", "AwsSignatureV4Auth"] + + +class NoneAuth(TypedDict, total=False): + name: Required[str] + """Origin group name.""" + + auth_type: str + """Origin authentication type. + + Possible values: + + - **none** - Used for public origins. + - **awsSignatureV4** - Used for S3 storage. + """ + + path: str + """Parameter is **deprecated**.""" + + proxy_next_upstream: SequenceNotStr[str] + """Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + """ + + sources: Iterable[NoneAuthSource] + """List of origin sources in the origin group.""" + + use_next: bool + """ + Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class NoneAuthSource(TypedDict, total=False): + backup: bool + """ + Defines whether the origin is a backup, meaning that it will not be used until + one of active origins become unavailable. + + Possible values: + + - **true** - Origin is a backup. + - **false** - Origin is not a backup. + """ + + enabled: bool + """Enables or disables an origin source in the origin group. + + Possible values: + + - **true** - Origin is enabled and the CDN uses it to pull content. + - **false** - Origin is disabled and the CDN does not use it to pull content. + + Origin group must contain at least one enabled origin. + """ + + source: str + """IP address or domain name of the origin and the port, if custom port is used.""" + + +class AwsSignatureV4(TypedDict, total=False): + auth: AwsSignatureV4Auth + """Credentials to access the private bucket.""" + + auth_type: str + """Authentication type. + + **awsSignatureV4** value is used for S3 storage. + """ + + name: str + """Origin group name.""" + + path: str + """Parameter is **deprecated**.""" + + proxy_next_upstream: SequenceNotStr[str] + """Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + """ + + use_next: bool + """ + Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class AwsSignatureV4Auth(TypedDict, total=False): + """Credentials to access the private bucket.""" + + s3_access_key_id: Required[str] + """Access key ID for the S3 account. + + Restrictions: + + - Latin letters (A-Z, a-z), numbers (0-9), colon, dash, and underscore. + - From 3 to 512 characters. + """ + + s3_bucket_name: Required[str] + """S3 bucket name. + + Restrictions: + + - Maximum 128 characters. + """ + + s3_secret_access_key: Required[str] + """Secret access key for the S3 account. + + Restrictions: + + - Latin letters (A-Z, a-z), numbers (0-9), pluses, slashes, dashes, colons and + underscores. + - If "s3_type": amazon, length should be 40 characters. + - If "s3_type": other, length should be from 16 to 255 characters. + """ + + s3_type: Required[str] + """Storage type compatible with S3. + + Possible values: + + - **amazon** – AWS S3 storage. + - **other** – Other (not AWS) S3 compatible storage. + """ + + s3_region: str + """S3 storage region. + + The parameter is required, if "s3_type": amazon. + """ + + s3_storage_hostname: str + """S3 storage hostname. + + The parameter is required, if "s3_type": other. + """ + + +OriginGroupUpdateParams: TypeAlias = Union[NoneAuth, AwsSignatureV4] diff --git a/src/gcore/types/cdn/origin_groups.py b/src/gcore/types/cdn/origin_groups.py new file mode 100644 index 00000000..863ea739 --- /dev/null +++ b/src/gcore/types/cdn/origin_groups.py @@ -0,0 +1,214 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["OriginGroups", "NoneAuth", "NoneAuthSource", "AwsSignatureV4", "AwsSignatureV4Auth"] + + +class NoneAuthSource(BaseModel): + backup: Optional[bool] = None + """ + Defines whether the origin is a backup, meaning that it will not be used until + one of active origins become unavailable. + + Possible values: + + - **true** - Origin is a backup. + - **false** - Origin is not a backup. + """ + + enabled: Optional[bool] = None + """Enables or disables an origin source in the origin group. + + Possible values: + + - **true** - Origin is enabled and the CDN uses it to pull content. + - **false** - Origin is disabled and the CDN does not use it to pull content. + + Origin group must contain at least one enabled origin. + """ + + source: Optional[str] = None + """IP address or domain name of the origin and the port, if custom port is used.""" + + +class NoneAuth(BaseModel): + id: Optional[int] = None + """Origin group ID.""" + + auth_type: Optional[str] = None + """Origin authentication type. + + Possible values: + + - **none** - Used for public origins. + - **awsSignatureV4** - Used for S3 storage. + """ + + has_related_resources: Optional[bool] = None + """Defines whether the origin group has related CDN resources. + + Possible values: + + - **true** - Origin group has related CDN resources. + - **false** - Origin group does not have related CDN resources. + """ + + name: Optional[str] = None + """Origin group name.""" + + path: Optional[str] = None + """Parameter is **deprecated**.""" + + proxy_next_upstream: Optional[List[str]] = None + """Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + """ + + sources: Optional[List[NoneAuthSource]] = None + """List of origin sources in the origin group.""" + + use_next: Optional[bool] = None + """ + Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class AwsSignatureV4Auth(BaseModel): + """Credentials to access the private bucket.""" + + s3_access_key_id: str + """Access key ID for the S3 account. + + Restrictions: + + - Latin letters (A-Z, a-z), numbers (0-9), colon, dash, and underscore. + - From 3 to 512 characters. + """ + + s3_bucket_name: str + """S3 bucket name. + + Restrictions: + + - Maximum 128 characters. + """ + + s3_secret_access_key: str + """Secret access key for the S3 account. + + Restrictions: + + - Latin letters (A-Z, a-z), numbers (0-9), pluses, slashes, dashes, colons and + underscores. + - If "s3_type": amazon, length should be 40 characters. + - If "s3_type": other, length should be from 16 to 255 characters. + """ + + s3_type: str + """Storage type compatible with S3. + + Possible values: + + - **amazon** – AWS S3 storage. + - **other** – Other (not AWS) S3 compatible storage. + """ + + s3_region: Optional[str] = None + """S3 storage region. + + The parameter is required, if "s3_type": amazon. + """ + + s3_storage_hostname: Optional[str] = None + """S3 storage hostname. + + The parameter is required, if "s3_type": other. + """ + + +class AwsSignatureV4(BaseModel): + id: Optional[int] = None + """Origin group ID.""" + + auth: Optional[AwsSignatureV4Auth] = None + """Credentials to access the private bucket.""" + + auth_type: Optional[str] = None + """Authentication type. + + **awsSignatureV4** value is used for S3 storage. + """ + + has_related_resources: Optional[bool] = None + """Defines whether the origin group has related CDN resources. + + Possible values: + + - **true** - Origin group has related CDN resources. + - **false** - Origin group does not have related CDN resources. + """ + + name: Optional[str] = None + """Origin group name.""" + + path: Optional[str] = None + """Parameter is **deprecated**.""" + + proxy_next_upstream: Optional[List[str]] = None + """Defines cases when the request should be passed on to the next origin. + + Possible values: + + - **error** - an error occurred while establishing a connection with the origin, + passing a request to it, or reading the response header + - **timeout** - a timeout has occurred while establishing a connection with the + origin, passing a request to it, or reading the response header + - **`invalid_header`** - a origin returned an empty or invalid response + - **`http_403`** - a origin returned a response with the code 403 + - **`http_404`** - a origin returned a response with the code 404 + - **`http_429`** - a origin returned a response with the code 429 + - **`http_500`** - a origin returned a response with the code 500 + - **`http_502`** - a origin returned a response with the code 502 + - **`http_503`** - a origin returned a response with the code 503 + - **`http_504`** - a origin returned a response with the code 504 + """ + + use_next: Optional[bool] = None + """ + Defines whether to use the next origin from the origin group if origin responds + with the cases specified in `proxy_next_upstream`. If you enable it, you must + specify cases in `proxy_next_upstream`. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +OriginGroups: TypeAlias = Union[NoneAuth, AwsSignatureV4] diff --git a/src/gcore/types/cdn/origin_groups_list.py b/src/gcore/types/cdn/origin_groups_list.py new file mode 100644 index 00000000..248241d2 --- /dev/null +++ b/src/gcore/types/cdn/origin_groups_list.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .origin_groups import OriginGroups + +__all__ = ["OriginGroupsList"] + +OriginGroupsList: TypeAlias = List[OriginGroups] diff --git a/src/gcore/types/cdn/public_ip_list.py b/src/gcore/types/cdn/public_ip_list.py new file mode 100644 index 00000000..ce8272df --- /dev/null +++ b/src/gcore/types/cdn/public_ip_list.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["PublicIPList"] + + +class PublicIPList(BaseModel): + addresses: Optional[List[str]] = None + """List of IPv4 addresses.""" + + addresses_v6: Optional[List[str]] = None + """List of IPv6 addresses.""" diff --git a/src/gcore/types/cdn/public_network_list.py b/src/gcore/types/cdn/public_network_list.py new file mode 100644 index 00000000..2cc5570d --- /dev/null +++ b/src/gcore/types/cdn/public_network_list.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["PublicNetworkList"] + + +class PublicNetworkList(BaseModel): + addresses: Optional[List[str]] = None + """List of IPv4 networks.""" + + addresses_v6: Optional[List[str]] = None + """List of IPv6 networks.""" diff --git a/src/gcore/types/cdn/purge_status.py b/src/gcore/types/cdn/purge_status.py new file mode 100644 index 00000000..2ac5c9f3 --- /dev/null +++ b/src/gcore/types/cdn/purge_status.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["PurgeStatus", "Resource"] + + +class Resource(BaseModel): + id: Optional[int] = None + """Resource ID.""" + + cname: Optional[str] = None + """CNAME of the resource.""" + + +class PurgeStatus(BaseModel): + created: Optional[str] = None + """Date and time when the purge was created (ISO 8601/RFC 3339 format, UTC).""" + + payload: Optional[object] = None + """Purge payload depends on purge type. + + Possible values: + + - **urls** - Purge by URL. + - **paths** - Purge by Pattern and purge All. + """ + + purge_id: Optional[int] = None + """Purge ID.""" + + purge_type: Optional[str] = None + """Contains the name of the purge request type. + + Possible values: + + - **`purge_by_pattern`** - Purge by Pattern. + - **`purge_by_url`** - Purge by URL. + - **`purge_all`** - Purge All. + """ + + resource: Optional[Resource] = None + + status: Optional[Literal["In progress", "Successful", "Failed"]] = None + """Purge status. + + Possible values: + + - **In progress** - Purge is in progress. + - **Successful** - Purge was successful. + - **Failed** - Purge failed. + """ diff --git a/src/gcore/types/cdn/resource_aggregated_stats.py b/src/gcore/types/cdn/resource_aggregated_stats.py new file mode 100644 index 00000000..5d6453a2 --- /dev/null +++ b/src/gcore/types/cdn/resource_aggregated_stats.py @@ -0,0 +1,80 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["ResourceAggregatedStats"] + + +class ResourceAggregatedStats(BaseModel): + api_1_example: Optional[object] = FieldInfo(alias="1 (example)", default=None) + """CDN resource ID for which statistics data is shown.""" + + api_95_percentile: Optional[int] = FieldInfo(alias="95_percentile", default=None) + """95 percentile bandwidth value""" + + backblaze_bytes: Optional[int] = None + """Traffic in bytes from Backblaze origin.""" + + cache_hit_traffic_ratio: Optional[int] = None + """Formula: 1 - `upstream_bytes` / `sent_bytes`. + + We deduct the non-cached traffic from the total traffic amount + """ + + cis_example: Optional[object] = FieldInfo(alias="cis (example)", default=None) + """Region by which statistics data is grouped.""" + + max_bandwidth: Optional[int] = None + """Maximum bandwidth""" + + metrics: Optional[object] = None + """Statistics parameters.""" + + min_bandwidth: Optional[int] = None + """Minimum bandwidth""" + + region: Optional[object] = None + """Regions by which statistics data is grouped.""" + + requests: Optional[int] = None + """Number of requests to edge servers.""" + + resource: Optional[object] = None + """Resources IDs by which statistics data is grouped.""" + + response_types: Optional[object] = None + """Statistics by content type. + + It returns a number of responses for content with different MIME types. + """ + + responses_2xx: Optional[int] = None + """Number of 2xx response codes.""" + + responses_3xx: Optional[int] = None + """Number of 3xx response codes.""" + + responses_4xx: Optional[int] = None + """Number of 4xx response codes.""" + + responses_5xx: Optional[int] = None + """Number of 5xx response codes.""" + + responses_hit: Optional[int] = None + """Number of responses with the header Cache: HIT.""" + + responses_miss: Optional[int] = None + """Number of responses with the header Cache: MISS.""" + + sent_bytes: Optional[int] = None + """Traffic in bytes from CDN servers to clients.""" + + total_bytes: Optional[int] = None + """Upstream bytes and `sent_bytes` combined.""" + + upstream_bytes: Optional[int] = None + """Traffic in bytes from the upstream to CDN servers.""" diff --git a/src/gcore/types/cdn/resource_usage_stats.py b/src/gcore/types/cdn/resource_usage_stats.py new file mode 100644 index 00000000..93e1fea7 --- /dev/null +++ b/src/gcore/types/cdn/resource_usage_stats.py @@ -0,0 +1,112 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["ResourceUsageStats"] + + +class ResourceUsageStats(BaseModel): + api_1_example: Optional[object] = FieldInfo(alias="1 (example)", default=None) + """ID of CDN resource for which statistics data is shown.""" + + backblaze_bytes: Optional[List[int]] = None + """BackBlaze bytes from Backblaze origin. + + Represented by two values: + + - 1543622400 — Time in the UNIX timestamp when statistics were received. + - 17329220573 — Bytes. + """ + + metrics: Optional[object] = None + """Types of statistics data. + + Possible values: + + - **`upstream_bytes`** – Traffic in bytes from an origin server to CDN servers + or to origin shielding when used. + - **`sent_bytes`** – Traffic in bytes from CDN servers to clients. + - **`shield_bytes`** – Traffic in bytes from origin shielding to CDN servers. + - **`backblaze_bytes`** - Traffic in bytes from Backblaze origin. + - **`total_bytes`** – `shield_bytes`, `upstream_bytes` and `sent_bytes` + combined. + - **`cdn_bytes`** – `sent_bytes` and `shield_bytes` combined. + - **requests** – Number of requests to edge servers. + - **`responses_2xx`** – Number of 2xx response codes. + - **`responses_3xx`** – Number of 3xx response codes. + - **`responses_4xx`** – Number of 4xx response codes. + - **`responses_5xx`** – Number of 5xx response codes. + - **`responses_hit`** – Number of responses with the header Cache: HIT. + - **`responses_miss`** – Number of responses with the header Cache: MISS. + - **`response_types`** – Statistics by content type. It returns a number of + responses for content with different MIME types. + - **`cache_hit_traffic_ratio`** – Formula: 1 - `upstream_bytes` / `sent_bytes`. + We deduct the non-cached traffic from the total traffic amount. + - **`cache_hit_requests_ratio`** – Formula: `responses_hit` / requests. The + share of sending cached content. + - **`shield_traffic_ratio`** – Formula: (`shield_bytes` - `upstream_bytes`) / + `shield_bytes`. The efficiency of the Origin Shielding: how much more traffic + is sent from the Origin Shielding than from the origin. + - **`image_processed`** - Number of images transformed on the Image optimization + service. + - **`request_time`** - Time elapsed between the first bytes of a request were + processed and logging after the last bytes were sent to a user. + - **`upstream_response_time`** - Number of milliseconds it took to receive a + response from an origin. If upstream `response_time_` contains several + indications for one request (in case of more than 1 origin), we summarize + them. In case of aggregating several queries, the average of this amount is + calculated. + + Metrics **`upstream_response_time`** and **`request_time`** should be requested + separately from other metrics + """ + + region: Optional[object] = None + """Regions for which data is displayed. + + Possible values: + + - **na** – North America + - **eu** – Europe + - **cis** – Commonwealth of Independent States + - **asia** – Asia + - **au** – Australia + - **latam** – Latin America + - **me** – Middle East + - **africa** - Africa + - **sa** - South America + """ + + resource: Optional[object] = None + """Resources IDs by which statistics data is grouped.""" + + sent_bytes: Optional[List[int]] = None + """Bytes from CDN servers to the end-users. + + Represented by two values: + + - 1543622400 — Time in the UNIX timestamp when statistics were received. + - 17329220573 — Bytes. + """ + + total_bytes: Optional[List[int]] = None + """Upstream bytes and `sent_bytes` combined. + + Represented by two values: + + - 1543622400 — Time in the UNIX timestamp when statistics were received. + - 17329220573 — Bytes. + """ + + upstream_bytes: Optional[List[int]] = None + """Bytes from the upstream to the CDN servers. + + Represented by two values: + + - 1543622400 — Time in the UNIX timestamp when statistics were received. + - 17329220573 — Bytes. + """ diff --git a/src/gcore/types/cdn/rule_template.py b/src/gcore/types/cdn/rule_template.py new file mode 100644 index 00000000..a2eb3725 --- /dev/null +++ b/src/gcore/types/cdn/rule_template.py @@ -0,0 +1,1954 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = [ + "RuleTemplate", + "Options", + "OptionsAllowedHTTPMethods", + "OptionsBotProtection", + "OptionsBotProtectionBotChallenge", + "OptionsBrotliCompression", + "OptionsBrowserCacheSettings", + "OptionsCacheHTTPHeaders", + "OptionsCors", + "OptionsCountryACL", + "OptionsDisableCache", + "OptionsDisableProxyForceRanges", + "OptionsEdgeCacheSettings", + "OptionsFastedge", + "OptionsFastedgeOnRequestBody", + "OptionsFastedgeOnRequestHeaders", + "OptionsFastedgeOnResponseBody", + "OptionsFastedgeOnResponseHeaders", + "OptionsFetchCompressed", + "OptionsFollowOriginRedirect", + "OptionsForceReturn", + "OptionsForceReturnTimeInterval", + "OptionsForwardHostHeader", + "OptionsGzipOn", + "OptionsHostHeader", + "OptionsIgnoreCookie", + "OptionsIgnoreQueryString", + "OptionsImageStack", + "OptionsIPAddressACL", + "OptionsLimitBandwidth", + "OptionsProxyCacheKey", + "OptionsProxyCacheMethodsSet", + "OptionsProxyConnectTimeout", + "OptionsProxyReadTimeout", + "OptionsQueryParamsBlacklist", + "OptionsQueryParamsWhitelist", + "OptionsQueryStringForwarding", + "OptionsRedirectHTTPToHTTPS", + "OptionsRedirectHTTPSToHTTP", + "OptionsReferrerACL", + "OptionsRequestLimiter", + "OptionsResponseHeadersHidingPolicy", + "OptionsRewrite", + "OptionsSecureKey", + "OptionsSlice", + "OptionsSni", + "OptionsStale", + "OptionsStaticResponseHeaders", + "OptionsStaticResponseHeadersValue", + "OptionsStaticHeaders", + "OptionsStaticRequestHeaders", + "OptionsUserAgentACL", + "OptionsWaap", + "OptionsWebsockets", +] + + +class OptionsAllowedHTTPMethods(BaseModel): + """HTTP methods allowed for content requests from the CDN.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[Literal["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]] + + +class OptionsBotProtectionBotChallenge(BaseModel): + """Controls the bot challenge module state.""" + + enabled: Optional[bool] = None + """Possible values: + + - **true** - Bot challenge is enabled. + - **false** - Bot challenge is disabled. + """ + + +class OptionsBotProtection(BaseModel): + """ + Allows to prevent online services from overloading and ensure your business workflow running smoothly. + """ + + bot_challenge: OptionsBotProtectionBotChallenge + """Controls the bot challenge module state.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsBrotliCompression(BaseModel): + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN resource and want to enable `brotli_compression` in a rule, you must specify `fetch_compressed:false` in the rule. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[ + Literal[ + "application/javascript", + "application/json", + "application/vnd.ms-fontobject", + "application/wasm", + "application/x-font-ttf", + "application/x-javascript", + "application/xml", + "application/xml+rss", + "image/svg+xml", + "image/x-icon", + "text/css", + "text/html", + "text/javascript", + "text/plain", + "text/xml", + ] + ] + """Allows to select the content types you want to compress. + + `text/html` is a mandatory content type. + """ + + +class OptionsBrowserCacheSettings(BaseModel): + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Set the cache expiration time to '0s' to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsCacheHTTPHeaders(BaseModel): + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[str] + + +class OptionsCors(BaseModel): + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header to a response to a browser. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[str] + """Value of the Access-Control-Allow-Origin header. + + Possible values: + + - **Adds \\** as the Access-Control-Allow-Origin header value** - Content will be + uploaded for requests from any domain. `"value": ["*"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value if the + origin matches one of the listed domains** - Content will be uploaded only for + requests from the domains specified in the field. + `"value": ["domain.com", "second.dom.com"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value** - + Content will be uploaded for requests from any domain, and the domain from + which the request was sent will be added to the "Access-Control-Allow-Origin" + header in the response. `"value": ["$http_origin"]` + """ + + always: Optional[bool] = None + """ + Defines whether the Access-Control-Allow-Origin header should be added to a + response from CDN regardless of response code. + + Possible values: + + - **true** - Header will be added to a response regardless of response code. + - **false** - Header will only be added to responses with codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsCountryACL(BaseModel): + """Enables control access to content for specified countries.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: List[str] + """List of countries according to ISO-3166-1. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of countries for which access is prohibited. + - **deny** - List of countries for which access is allowed. + """ + + policy_type: Literal["allow", "deny"] + """Defines the type of CDN resource access policy. + + Possible values: + + - **allow** - Access is allowed for all the countries except for those specified + in `excepted_values` field. + - **deny** - Access is denied for all the countries except for those specified + in `excepted_values` field. + """ + + +class OptionsDisableCache(BaseModel): + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - content caching is disabled. + - **false** - content caching is enabled. + """ + + +class OptionsDisableProxyForceRanges(BaseModel): + """Allows 206 responses regardless of the settings of an origin source.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsEdgeCacheSettings(BaseModel): + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + custom_values: Optional[Dict[str, str]] = None + """ + A MAP object representing the caching time in seconds for a response with a + specific response code. + + These settings have a higher priority than the `value` field. + + - Use `any` key to specify caching time for all response codes. + - Use `0s` value to disable caching for a specific response code. + """ + + default: Optional[str] = None + """Enables content caching according to the origin cache settings. + + The value is applied to the following response codes 200, 201, 204, 206, 301, + 302, 303, 304, 307, 308, if an origin server does not have caching HTTP headers. + + Responses with other codes will not be cached. + + The maximum duration is any equivalent to `1y`. + """ + + value: Optional[str] = None + """Caching time. + + The value is applied to the following response codes: 200, 206, 301, 302. + Responses with codes 4xx, 5xx will not be cached. + + Use `0s` to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsFastedgeOnRequestBody(BaseModel): + """ + Allows to configure FastEdge application that will be called to handle request body as soon as CDN receives incoming HTTP request. + """ + + app_id: str + """The ID of the application in FastEdge.""" + + enabled: Optional[bool] = None + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: Optional[bool] = None + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: Optional[bool] = None + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: Optional[bool] = None + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnRequestHeaders(BaseModel): + """ + Allows to configure FastEdge application that will be called to handle request headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + app_id: str + """The ID of the application in FastEdge.""" + + enabled: Optional[bool] = None + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: Optional[bool] = None + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: Optional[bool] = None + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: Optional[bool] = None + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseBody(BaseModel): + """ + Allows to configure FastEdge application that will be called to handle response body before CDN sends the HTTP response. + """ + + app_id: str + """The ID of the application in FastEdge.""" + + enabled: Optional[bool] = None + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: Optional[bool] = None + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: Optional[bool] = None + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: Optional[bool] = None + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseHeaders(BaseModel): + """ + Allows to configure FastEdge application that will be called to handle response headers before CDN sends the HTTP response. + """ + + app_id: str + """The ID of the application in FastEdge.""" + + enabled: Optional[bool] = None + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: Optional[bool] = None + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: Optional[bool] = None + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: Optional[bool] = None + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedge(BaseModel): + """ + Allows to configure FastEdge app to be called on different request/response phases. + + Note: At least one of `on_request_headers`, `on_request_body`, `on_response_headers`, or `on_response_body` must be specified. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + on_request_body: Optional[OptionsFastedgeOnRequestBody] = None + """ + Allows to configure FastEdge application that will be called to handle request + body as soon as CDN receives incoming HTTP request. + """ + + on_request_headers: Optional[OptionsFastedgeOnRequestHeaders] = None + """ + Allows to configure FastEdge application that will be called to handle request + headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + on_response_body: Optional[OptionsFastedgeOnResponseBody] = None + """ + Allows to configure FastEdge application that will be called to handle response + body before CDN sends the HTTP response. + """ + + on_response_headers: Optional[OptionsFastedgeOnResponseHeaders] = None + """ + Allows to configure FastEdge application that will be called to handle response + headers before CDN sends the HTTP response. + """ + + +class OptionsFetchCompressed(BaseModel): + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If you enable it in CDN resource and want to use `gzipON` and `brotli_compression` in a rule, you have to specify `"fetch_compressed": false` in the rule. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsFollowOriginRedirect(BaseModel): + """ + Enables redirection from origin. + If the origin server returns a redirect, the option allows the CDN to pull the requested content from the origin server that was returned in the redirect. + """ + + codes: List[Literal[301, 302, 303, 307, 308]] + """Redirect status code that the origin server returns. + + To serve up to date content to end users, you will need to purge the cache after + managing the option. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsForceReturnTimeInterval(BaseModel): + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + end_time: str + """Time until which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + start_time: str + """Time from which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + time_zone: Optional[str] = None + """Time zone used to calculate time.""" + + +class OptionsForceReturn(BaseModel): + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + body: str + """URL for redirection or text.""" + + code: int + """Status code value.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + time_interval: Optional[OptionsForceReturnTimeInterval] = None + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + +class OptionsForwardHostHeader(BaseModel): + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsGzipOn(BaseModel): + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in rules. If you enable `fetch_compressed` in CDN resource and want to enable `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsHostHeader(BaseModel): + """ + Sets the Host header that CDN servers use when request content from an origin server. + Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Host Header value.""" + + +class OptionsIgnoreCookie(BaseModel): + """ + Defines whether the files with the Set-Cookies header are cached as one file or as different ones. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled, files with cookies are cached as one file. + - **false** - Option is disabled, files with cookies are cached as different + files. + """ + + +class OptionsIgnoreQueryString(BaseModel): + """ + How a file with different query strings is cached: either as one object (option is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsImageStack(BaseModel): + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically converts them to WebP or AVIF format. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + avif_enabled: Optional[bool] = None + """Enables or disables automatic conversion of JPEG and PNG images to AVI format.""" + + png_lossless: Optional[bool] = None + """Enables or disables compression without quality loss for PNG format.""" + + quality: Optional[int] = None + """Defines quality settings for JPG and PNG images. + + The higher the value, the better the image quality, and the larger the file size + after conversion. + """ + + webp_enabled: Optional[bool] = None + """Enables or disables automatic conversion of JPEG and PNG images to WebP format.""" + + +class OptionsIPAddressACL(BaseModel): + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: List[str] + """List of IP addresses with a subnet mask. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of IP addresses for which access is prohibited. + - **deny** - List of IP addresses for which access is allowed. + + Examples: + + - `192.168.3.2/32` + - `2a03:d000:2980:7::8/128` + """ + + policy_type: Literal["allow", "deny"] + """IP access policy type. + + Possible values: + + - **allow** - Allow access to all IPs except IPs specified in "excepted_values" + field. + - **deny** - Deny access to all IPs except IPs specified in "excepted_values" + field. + """ + + +class OptionsLimitBandwidth(BaseModel): + """Allows to control the download speed per connection.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + limit_type: Literal["static", "dynamic"] + """Method of controlling the download speed per connection. + + Possible values: + + - **static** - Use speed and buffer fields to set the download speed limit. + - **dynamic** - Use query strings **speed** and **buffer** to set the download + speed limit. + + For example, when requesting content at the link + + ``` + http://cdn.example.com/video.mp4?speed=50k&buffer=500k + ``` + + the download speed will be limited to 50kB/s after 500 kB. + """ + + buffer: Optional[int] = None + """Amount of downloaded data after which the user will be rate limited.""" + + speed: Optional[int] = None + """Maximum download speed per connection.""" + + +class OptionsProxyCacheKey(BaseModel): + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will not work. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Key for caching.""" + + +class OptionsProxyCacheMethodsSet(BaseModel): + """Caching for POST requests along with default GET and HEAD.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsProxyConnectTimeout(BaseModel): + """The time limit for establishing a connection with the origin.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Timeout value in seconds. + + Supported range: **1s - 5s**. + """ + + +class OptionsProxyReadTimeout(BaseModel): + """ + The time limit for receiving a partial response from the origin. + If no response is received within this time, the connection will be closed. + + **Note:** + When used with a WebSocket connection, this option supports values only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: str + """Timeout value in seconds. + + Supported range: **1s - 30s**. + """ + + +class OptionsQueryParamsBlacklist(BaseModel): + """ + Files with the specified query parameters are cached as one object, files with other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[str] + """List of query parameters.""" + + +class OptionsQueryParamsWhitelist(BaseModel): + """ + Files with the specified query parameters are cached as different objects, files with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[str] + """List of query parameters.""" + + +class OptionsQueryStringForwarding(BaseModel): + """ + The Query String Forwarding feature allows for the seamless transfer of parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication tokens or tracking information, are consistently passed along from the playlist manifest to the individual media segments. + This is particularly useful for maintaining continuity in security, analytics, and any other parameter-based operations across the entire media delivery workflow. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + forward_from_file_types: List[str] + """ + The `forward_from_files_types` field specifies the types of playlist files from + which parameters will be extracted and forwarded. This typically includes + formats that list multiple media chunk references, such as HLS and DASH + playlists. Parameters associated with these playlist files (like query strings + or headers) will be propagated to the chunks they reference. + """ + + forward_to_file_types: List[str] + """ + The field specifies the types of media chunk files to which parameters, + extracted from playlist files, will be forwarded. These refer to the actual + segments of media content that are delivered to viewers. Ensuring the correct + parameters are forwarded to these files is crucial for maintaining the integrity + of the streaming session. + """ + + forward_except_keys: Optional[List[str]] = None + """ + The `forward_except_keys` field provides a mechanism to exclude specific + parameters from being forwarded from playlist files to media chunk files. By + listing certain keys in this field, you can ensure that these parameters are + omitted during the forwarding process. This is particularly useful for + preventing sensitive or irrelevant information from being included in requests + for media chunks, thereby enhancing security and optimizing performance. + """ + + forward_only_keys: Optional[List[str]] = None + """ + The `forward_only_keys` field allows for granular control over which specific + parameters are forwarded from playlist files to media chunk files. By specifying + certain keys, only those parameters will be propagated, ensuring that only + relevant information is passed along. This is particularly useful for security + and performance optimization, as it prevents unnecessary or sensitive data from + being included in requests for media chunks. + """ + + +class OptionsRedirectHTTPToHTTPS(BaseModel): + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsRedirectHTTPSToHTTP(BaseModel): + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsReferrerACL(BaseModel): + """Controls access to the CDN resource content for specified domain names.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: List[str] + """ + List of domain names or wildcard domains (without protocol: `http://` or + `https://`.) + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of domain names for which access is prohibited. + - **deny** - List of IP domain names for which access is allowed. + + Examples: + + - `example.com` + - `*.example.com` + """ + + policy_type: Literal["allow", "deny"] + """Policy type. + + Possible values: + + - **allow** - Allow access to all domain names except the domain names specified + in `excepted_values` field. + - **deny** - Deny access to all domain names except the domain names specified + in `excepted_values` field. + """ + + +class OptionsRequestLimiter(BaseModel): + """Option allows to limit the amount of HTTP requests.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + rate: int + """Maximum request rate.""" + + burst: Optional[int] = None + + delay: Optional[int] = None + + rate_unit: Optional[Literal["r/s", "r/m"]] = None + """Units of measurement for the `rate` field. + + Possible values: + + - **r/s** - Requests per second. + - **r/m** - Requests per minute. + + If the rate is less than one request per second, it is specified in request per + minute (r/m.) + """ + + +class OptionsResponseHeadersHidingPolicy(BaseModel): + """Hides HTTP headers from an origin server in the CDN response.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted: List[str] + """List of HTTP headers. + + Parameter meaning depends on the value of the `mode` field: + + - **show** - List of HTTP headers to hide from response. + - **hide** - List of HTTP headers to include in response. Other HTTP headers + will be hidden. + + The following headers are required and cannot be hidden from response: + + - `Connection` + - `Content-Length` + - `Content-Type` + - `Date` + - `Server` + """ + + mode: Literal["hide", "show"] + """How HTTP headers are hidden from the response. + + Possible values: + + - **show** - Hide only HTTP headers listed in the `excepted` field. + - **hide** - Hide all HTTP headers except headers listed in the "excepted" + field. + """ + + +class OptionsRewrite(BaseModel): + """Changes and redirects requests from the CDN to the origin. + + It operates according to the [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) configuration. + """ + + body: str + """Path for the Rewrite option. + + Example: + + - `/(.*) /media/$1` + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + flag: Optional[Literal["break", "last", "redirect", "permanent"]] = None + """Flag for the Rewrite option. + + Possible values: + + - **last** - Stop processing the current set of `ngx_http_rewrite_module` + directives and start a search for a new location matching changed URI. + - **break** - Stop processing the current set of the Rewrite option. + - **redirect** - Return a temporary redirect with the 302 code; used when a + replacement string does not start with `http://`, `https://`, or `$scheme`. + - **permanent** - Return a permanent redirect with the 301 code. + """ + + +class OptionsSecureKey(BaseModel): + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + key: Optional[str] = None + """Key generated on your side that will be used for URL signing.""" + + type: Optional[Literal[0, 2]] = None + """Type of URL signing. + + Possible types: + + - **Type 0** - Includes end user IP to secure token generation. + - **Type 2** - Excludes end user IP from secure token generation. + """ + + +class OptionsSlice(BaseModel): + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per part.) This reduces time to first byte. + + The option is based on the [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` options enabled. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsSni(BaseModel): + """ + The hostname that is added to SNI requests from CDN servers to the origin server via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not have a dedicated IP address. + If the origin server presents multiple certificates, SNI allows the origin server to know which certificate to use for the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + custom_hostname: str + """Custom SNI hostname. + + It is required if `sni_type` is set to custom. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + sni_type: Optional[Literal["dynamic", "custom"]] = None + """SNI (Server Name Indication) type. + + Possible values: + + - **dynamic** - SNI hostname depends on `hostHeader` and `forward_host_header` + options. It has several possible combinations: + - If the `hostHeader` option is enabled and specified, SNI hostname matches the + Host header. + - If the `forward_host_header` option is enabled and has true value, SNI + hostname matches the Host header used in the request made to a CDN. + - If the `hostHeader` and `forward_host_header` options are disabled, SNI + hostname matches the primary CNAME. + - **custom** - custom SNI hostname is in use. + """ + + +class OptionsStale(BaseModel): + """Serves stale cached content in case of origin unavailability.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[ + Literal[ + "error", + "http_403", + "http_404", + "http_429", + "http_500", + "http_502", + "http_503", + "http_504", + "invalid_header", + "timeout", + "updating", + ] + ] + """Defines list of errors for which "Always online" option is applied.""" + + +class OptionsStaticResponseHeadersValue(BaseModel): + name: str + """HTTP Header name. + + Restrictions: + + - Maximum 128 symbols. + - Latin letters (A-Z, a-z,) numbers (0-9,) dashes, and underscores only. + """ + + value: List[str] + """Header value. + + Restrictions: + + - Maximum 512 symbols. + - Letters (a-z), numbers (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ + /|\";:?.,><{}[]). + - Must start with a letter, number, asterisk or {. + - Multiple values can be added. + """ + + always: Optional[bool] = None + """ + Defines whether the header will be added to a response from CDN regardless of + response code. + + Possible values: + + - **true** - Header will be added to a response from CDN regardless of response + code. + - **false** - Header will be added only to the following response codes: 200, + 201, 204, 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsStaticResponseHeaders(BaseModel): + """Custom HTTP Headers that a CDN server adds to a response.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: List[OptionsStaticResponseHeadersValue] + + +class OptionsStaticHeaders(BaseModel): + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP Headers can be specified. May contain a header with multiple values. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: object + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 128 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsStaticRequestHeaders(BaseModel): + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Dict[str, str] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 255 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsUserAgentACL(BaseModel): + """Controls access to the content for specified User-Agents.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: List[str] + """List of User-Agents that will be allowed/denied. + + The meaning of the parameter depends on `policy_type`: + + - **allow** - List of User-Agents for which access is prohibited. + - **deny** - List of User-Agents for which access is allowed. + + You can provide exact User-Agent strings or regular expressions. Regular + expressions must start with `~` (case-sensitive) or `~*` (case-insensitive). + + Use an empty string `""` to allow/deny access when the User-Agent header is + empty. + """ + + policy_type: Literal["allow", "deny"] + """User-Agents policy type. + + Possible values: + + - **allow** - Allow access for all User-Agents except specified in + `excepted_values` field. + - **deny** - Deny access for all User-Agents except specified in + `excepted_values` field. + """ + + +class OptionsWaap(BaseModel): + """Allows to enable WAAP (Web Application and API Protection).""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsWebsockets(BaseModel): + """Enables or disables WebSockets connections to an origin server.""" + + enabled: bool + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: bool + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class Options(BaseModel): + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. + Option inherits its value from the CDN resource settings. + """ + + allowed_http_methods: Optional[OptionsAllowedHTTPMethods] = FieldInfo(alias="allowedHttpMethods", default=None) + """HTTP methods allowed for content requests from the CDN.""" + + bot_protection: Optional[OptionsBotProtection] = None + """ + Allows to prevent online services from overloading and ensure your business + workflow running smoothly. + """ + + brotli_compression: Optional[OptionsBrotliCompression] = None + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is + activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, + even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` + options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides + `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN + resource and want to enable `brotli_compression` in a rule, you must specify + `fetch_compressed:false` in the rule. + """ + + browser_cache_settings: Optional[OptionsBrowserCacheSettings] = None + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + cache_http_headers: Optional[OptionsCacheHTTPHeaders] = None + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + cors: Optional[OptionsCors] = None + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header + to a response to a browser. + """ + + country_acl: Optional[OptionsCountryACL] = None + """Enables control access to content for specified countries.""" + + disable_cache: Optional[OptionsDisableCache] = None + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + disable_proxy_force_ranges: Optional[OptionsDisableProxyForceRanges] = None + """Allows 206 responses regardless of the settings of an origin source.""" + + edge_cache_settings: Optional[OptionsEdgeCacheSettings] = None + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + fastedge: Optional[OptionsFastedge] = None + """ + Allows to configure FastEdge app to be called on different request/response + phases. + + Note: At least one of `on_request_headers`, `on_request_body`, + `on_response_headers`, or `on_response_body` must be specified. + """ + + fetch_compressed: Optional[OptionsFetchCompressed] = None + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress + your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or + `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If + you enable it in CDN resource and want to use `gzipON` and + `brotli_compression` in a rule, you have to specify + `"fetch_compressed": false` in the rule. + """ + + follow_origin_redirect: Optional[OptionsFollowOriginRedirect] = None + """ + Enables redirection from origin. If the origin server returns a redirect, the + option allows the CDN to pull the requested content from the origin server that + was returned in the redirect. + """ + + force_return: Optional[OptionsForceReturn] = None + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this + option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + forward_host_header: Optional[OptionsForwardHostHeader] = None + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + gzip_on: Optional[OptionsGzipOn] = FieldInfo(alias="gzipOn", default=None) + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` + options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in + rules. If you enable `fetch_compressed` in CDN resource and want to enable + `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + host_header: Optional[OptionsHostHeader] = FieldInfo(alias="hostHeader", default=None) + """ + Sets the Host header that CDN servers use when request content from an origin + server. Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + ignore_cookie: Optional[OptionsIgnoreCookie] = None + """ + Defines whether the files with the Set-Cookies header are cached as one file or + as different ones. + """ + + ignore_query_string: Optional[OptionsIgnoreQueryString] = FieldInfo(alias="ignoreQueryString", default=None) + """ + How a file with different query strings is cached: either as one object (option + is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + image_stack: Optional[OptionsImageStack] = None + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically + converts them to WebP or AVIF format. + """ + + ip_address_acl: Optional[OptionsIPAddressACL] = None + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, + you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. + [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + limit_bandwidth: Optional[OptionsLimitBandwidth] = None + """Allows to control the download speed per connection.""" + + proxy_cache_key: Optional[OptionsProxyCacheKey] = None + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache + and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will + not work. + """ + + proxy_cache_methods_set: Optional[OptionsProxyCacheMethodsSet] = None + """Caching for POST requests along with default GET and HEAD.""" + + proxy_connect_timeout: Optional[OptionsProxyConnectTimeout] = None + """The time limit for establishing a connection with the origin.""" + + proxy_read_timeout: Optional[OptionsProxyReadTimeout] = None + """ + The time limit for receiving a partial response from the origin. If no response + is received within this time, the connection will be closed. + + **Note:** When used with a WebSocket connection, this option supports values + only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + query_params_blacklist: Optional[OptionsQueryParamsBlacklist] = None + """ + Files with the specified query parameters are cached as one object, files with + other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_params_whitelist: Optional[OptionsQueryParamsWhitelist] = None + """ + Files with the specified query parameters are cached as different objects, files + with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_string_forwarding: Optional[OptionsQueryStringForwarding] = None + """ + The Query String Forwarding feature allows for the seamless transfer of + parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication + tokens or tracking information, are consistently passed along from the playlist + manifest to the individual media segments. This is particularly useful for + maintaining continuity in security, analytics, and any other parameter-based + operations across the entire media delivery workflow. + """ + + redirect_http_to_https: Optional[OptionsRedirectHTTPToHTTPS] = None + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + redirect_https_to_http: Optional[OptionsRedirectHTTPSToHTTP] = None + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + referrer_acl: Optional[OptionsReferrerACL] = None + """Controls access to the CDN resource content for specified domain names.""" + + request_limiter: Optional[OptionsRequestLimiter] = None + """Option allows to limit the amount of HTTP requests.""" + + response_headers_hiding_policy: Optional[OptionsResponseHeadersHidingPolicy] = None + """Hides HTTP headers from an origin server in the CDN response.""" + + rewrite: Optional[OptionsRewrite] = None + """Changes and redirects requests from the CDN to the origin. + + It operates according to the + [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) + configuration. + """ + + secure_key: Optional[OptionsSecureKey] = None + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + slice: Optional[OptionsSlice] = None + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per + part.) This reduces time to first byte. + + The option is based on the + [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` + options enabled. + """ + + sni: Optional[OptionsSni] = None + """ + The hostname that is added to SNI requests from CDN servers to the origin server + via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not + have a dedicated IP address. If the origin server presents multiple + certificates, SNI allows the origin server to know which certificate to use for + the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + stale: Optional[OptionsStale] = None + """Serves stale cached content in case of origin unavailability.""" + + static_response_headers: Optional[OptionsStaticResponseHeaders] = None + """Custom HTTP Headers that a CDN server adds to a response.""" + + static_headers: Optional[OptionsStaticHeaders] = FieldInfo(alias="staticHeaders", default=None) + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP + Headers can be specified. May contain a header with multiple values. + """ + + static_request_headers: Optional[OptionsStaticRequestHeaders] = FieldInfo( + alias="staticRequestHeaders", default=None + ) + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + user_agent_acl: Optional[OptionsUserAgentACL] = None + """Controls access to the content for specified User-Agents.""" + + waap: Optional[OptionsWaap] = None + """Allows to enable WAAP (Web Application and API Protection).""" + + websockets: Optional[OptionsWebsockets] = None + """Enables or disables WebSockets connections to an origin server.""" + + +class RuleTemplate(BaseModel): + id: Optional[int] = None + """Rule template ID.""" + + client: Optional[int] = None + """Client ID""" + + default: Optional[bool] = None + """Defines whether the template is a system template developed for common cases. + + System templates are available to all customers. + + Possible values: + + - **true** - Template is a system template and cannot be changed by a user. + - **false** - Template is a custom template and can be changed by a user. + """ + + deleted: Optional[bool] = None + """Defines whether the template has been deleted. + + Possible values: + + - **true** - Template has been deleted. + - **false** - Template has not been deleted. + """ + + name: Optional[str] = None + """Rule template name.""" + + options: Optional[Options] = None + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + """ + + override_origin_protocol: Optional[Literal["HTTPS", "HTTP", "MATCH"]] = FieldInfo( + alias="overrideOriginProtocol", default=None + ) + """ + Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + """ + + rule: Optional[str] = None + """Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + """ + + rule_type: Optional[int] = FieldInfo(alias="ruleType", default=None) + """Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + """ + + template: Optional[bool] = None + """Determines whether the rule is a template.""" + + weight: Optional[int] = None + """Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + """ diff --git a/src/gcore/types/cdn/rule_template_create_params.py b/src/gcore/types/cdn/rule_template_create_params.py new file mode 100644 index 00000000..1a4d8a41 --- /dev/null +++ b/src/gcore/types/cdn/rule_template_create_params.py @@ -0,0 +1,1924 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable, Optional +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = [ + "RuleTemplateCreateParams", + "Options", + "OptionsAllowedHTTPMethods", + "OptionsBotProtection", + "OptionsBotProtectionBotChallenge", + "OptionsBrotliCompression", + "OptionsBrowserCacheSettings", + "OptionsCacheHTTPHeaders", + "OptionsCors", + "OptionsCountryACL", + "OptionsDisableCache", + "OptionsDisableProxyForceRanges", + "OptionsEdgeCacheSettings", + "OptionsFastedge", + "OptionsFastedgeOnRequestBody", + "OptionsFastedgeOnRequestHeaders", + "OptionsFastedgeOnResponseBody", + "OptionsFastedgeOnResponseHeaders", + "OptionsFetchCompressed", + "OptionsFollowOriginRedirect", + "OptionsForceReturn", + "OptionsForceReturnTimeInterval", + "OptionsForwardHostHeader", + "OptionsGzipOn", + "OptionsHostHeader", + "OptionsIgnoreCookie", + "OptionsIgnoreQueryString", + "OptionsImageStack", + "OptionsIPAddressACL", + "OptionsLimitBandwidth", + "OptionsProxyCacheKey", + "OptionsProxyCacheMethodsSet", + "OptionsProxyConnectTimeout", + "OptionsProxyReadTimeout", + "OptionsQueryParamsBlacklist", + "OptionsQueryParamsWhitelist", + "OptionsQueryStringForwarding", + "OptionsRedirectHTTPToHTTPS", + "OptionsRedirectHTTPSToHTTP", + "OptionsReferrerACL", + "OptionsRequestLimiter", + "OptionsResponseHeadersHidingPolicy", + "OptionsRewrite", + "OptionsSecureKey", + "OptionsSlice", + "OptionsSni", + "OptionsStale", + "OptionsStaticResponseHeaders", + "OptionsStaticResponseHeadersValue", + "OptionsStaticHeaders", + "OptionsStaticRequestHeaders", + "OptionsUserAgentACL", + "OptionsWaap", + "OptionsWebsockets", +] + + +class RuleTemplateCreateParams(TypedDict, total=False): + rule: Required[str] + """Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + """ + + rule_type: Required[Annotated[int, PropertyInfo(alias="ruleType")]] + """Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + """ + + name: str + """Rule template name.""" + + options: Options + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + """ + + override_origin_protocol: Annotated[ + Optional[Literal["HTTPS", "HTTP", "MATCH"]], PropertyInfo(alias="overrideOriginProtocol") + ] + """ + Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + """ + + weight: int + """Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + """ + + +class OptionsAllowedHTTPMethods(TypedDict, total=False): + """HTTP methods allowed for content requests from the CDN.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[List[Literal["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]]] + + +class OptionsBotProtectionBotChallenge(TypedDict, total=False): + """Controls the bot challenge module state.""" + + enabled: bool + """Possible values: + + - **true** - Bot challenge is enabled. + - **false** - Bot challenge is disabled. + """ + + +class OptionsBotProtection(TypedDict, total=False): + """ + Allows to prevent online services from overloading and ensure your business workflow running smoothly. + """ + + bot_challenge: Required[OptionsBotProtectionBotChallenge] + """Controls the bot challenge module state.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsBrotliCompression(TypedDict, total=False): + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN resource and want to enable `brotli_compression` in a rule, you must specify `fetch_compressed:false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "application/javascript", + "application/json", + "application/vnd.ms-fontobject", + "application/wasm", + "application/x-font-ttf", + "application/x-javascript", + "application/xml", + "application/xml+rss", + "image/svg+xml", + "image/x-icon", + "text/css", + "text/html", + "text/javascript", + "text/plain", + "text/xml", + ] + ] + ] + """Allows to select the content types you want to compress. + + `text/html` is a mandatory content type. + """ + + +class OptionsBrowserCacheSettings(TypedDict, total=False): + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Set the cache expiration time to '0s' to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsCacheHTTPHeaders(TypedDict, total=False): + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + + +class OptionsCors(TypedDict, total=False): + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header to a response to a browser. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """Value of the Access-Control-Allow-Origin header. + + Possible values: + + - **Adds \\** as the Access-Control-Allow-Origin header value** - Content will be + uploaded for requests from any domain. `"value": ["*"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value if the + origin matches one of the listed domains** - Content will be uploaded only for + requests from the domains specified in the field. + `"value": ["domain.com", "second.dom.com"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value** - + Content will be uploaded for requests from any domain, and the domain from + which the request was sent will be added to the "Access-Control-Allow-Origin" + header in the response. `"value": ["$http_origin"]` + """ + + always: bool + """ + Defines whether the Access-Control-Allow-Origin header should be added to a + response from CDN regardless of response code. + + Possible values: + + - **true** - Header will be added to a response regardless of response code. + - **false** - Header will only be added to responses with codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsCountryACL(TypedDict, total=False): + """Enables control access to content for specified countries.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of countries according to ISO-3166-1. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of countries for which access is prohibited. + - **deny** - List of countries for which access is allowed. + """ + + policy_type: Required[Literal["allow", "deny"]] + """Defines the type of CDN resource access policy. + + Possible values: + + - **allow** - Access is allowed for all the countries except for those specified + in `excepted_values` field. + - **deny** - Access is denied for all the countries except for those specified + in `excepted_values` field. + """ + + +class OptionsDisableCache(TypedDict, total=False): + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - content caching is disabled. + - **false** - content caching is enabled. + """ + + +class OptionsDisableProxyForceRanges(TypedDict, total=False): + """Allows 206 responses regardless of the settings of an origin source.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsEdgeCacheSettings(TypedDict, total=False): + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + custom_values: Dict[str, str] + """ + A MAP object representing the caching time in seconds for a response with a + specific response code. + + These settings have a higher priority than the `value` field. + + - Use `any` key to specify caching time for all response codes. + - Use `0s` value to disable caching for a specific response code. + """ + + default: str + """Enables content caching according to the origin cache settings. + + The value is applied to the following response codes 200, 201, 204, 206, 301, + 302, 303, 304, 307, 308, if an origin server does not have caching HTTP headers. + + Responses with other codes will not be cached. + + The maximum duration is any equivalent to `1y`. + """ + + value: str + """Caching time. + + The value is applied to the following response codes: 200, 206, 301, 302. + Responses with codes 4xx, 5xx will not be cached. + + Use `0s` to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsFastedgeOnRequestBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request body as soon as CDN receives incoming HTTP request. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnRequestHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response body before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response headers before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedge(TypedDict, total=False): + """ + Allows to configure FastEdge app to be called on different request/response phases. + + Note: At least one of `on_request_headers`, `on_request_body`, `on_response_headers`, or `on_response_body` must be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + on_request_body: OptionsFastedgeOnRequestBody + """ + Allows to configure FastEdge application that will be called to handle request + body as soon as CDN receives incoming HTTP request. + """ + + on_request_headers: OptionsFastedgeOnRequestHeaders + """ + Allows to configure FastEdge application that will be called to handle request + headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + on_response_body: OptionsFastedgeOnResponseBody + """ + Allows to configure FastEdge application that will be called to handle response + body before CDN sends the HTTP response. + """ + + on_response_headers: OptionsFastedgeOnResponseHeaders + """ + Allows to configure FastEdge application that will be called to handle response + headers before CDN sends the HTTP response. + """ + + +class OptionsFetchCompressed(TypedDict, total=False): + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If you enable it in CDN resource and want to use `gzipON` and `brotli_compression` in a rule, you have to specify `"fetch_compressed": false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsFollowOriginRedirect(TypedDict, total=False): + """ + Enables redirection from origin. + If the origin server returns a redirect, the option allows the CDN to pull the requested content from the origin server that was returned in the redirect. + """ + + codes: Required[Iterable[Literal[301, 302, 303, 307, 308]]] + """Redirect status code that the origin server returns. + + To serve up to date content to end users, you will need to purge the cache after + managing the option. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsForceReturnTimeInterval(TypedDict, total=False): + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + end_time: Required[str] + """Time until which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + start_time: Required[str] + """Time from which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + time_zone: str + """Time zone used to calculate time.""" + + +class OptionsForceReturn(TypedDict, total=False): + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + body: Required[str] + """URL for redirection or text.""" + + code: Required[int] + """Status code value.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + time_interval: Optional[OptionsForceReturnTimeInterval] + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + +class OptionsForwardHostHeader(TypedDict, total=False): + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsGzipOn(TypedDict, total=False): + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in rules. If you enable `fetch_compressed` in CDN resource and want to enable `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsHostHeader(TypedDict, total=False): + """ + Sets the Host header that CDN servers use when request content from an origin server. + Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Host Header value.""" + + +class OptionsIgnoreCookie(TypedDict, total=False): + """ + Defines whether the files with the Set-Cookies header are cached as one file or as different ones. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled, files with cookies are cached as one file. + - **false** - Option is disabled, files with cookies are cached as different + files. + """ + + +class OptionsIgnoreQueryString(TypedDict, total=False): + """ + How a file with different query strings is cached: either as one object (option is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsImageStack(TypedDict, total=False): + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically converts them to WebP or AVIF format. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + avif_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to AVI format.""" + + png_lossless: bool + """Enables or disables compression without quality loss for PNG format.""" + + quality: int + """Defines quality settings for JPG and PNG images. + + The higher the value, the better the image quality, and the larger the file size + after conversion. + """ + + webp_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to WebP format.""" + + +class OptionsIPAddressACL(TypedDict, total=False): + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of IP addresses with a subnet mask. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of IP addresses for which access is prohibited. + - **deny** - List of IP addresses for which access is allowed. + + Examples: + + - `192.168.3.2/32` + - `2a03:d000:2980:7::8/128` + """ + + policy_type: Required[Literal["allow", "deny"]] + """IP access policy type. + + Possible values: + + - **allow** - Allow access to all IPs except IPs specified in "excepted_values" + field. + - **deny** - Deny access to all IPs except IPs specified in "excepted_values" + field. + """ + + +class OptionsLimitBandwidth(TypedDict, total=False): + """Allows to control the download speed per connection.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + limit_type: Required[Literal["static", "dynamic"]] + """Method of controlling the download speed per connection. + + Possible values: + + - **static** - Use speed and buffer fields to set the download speed limit. + - **dynamic** - Use query strings **speed** and **buffer** to set the download + speed limit. + + For example, when requesting content at the link + + ``` + http://cdn.example.com/video.mp4?speed=50k&buffer=500k + ``` + + the download speed will be limited to 50kB/s after 500 kB. + """ + + buffer: int + """Amount of downloaded data after which the user will be rate limited.""" + + speed: int + """Maximum download speed per connection.""" + + +class OptionsProxyCacheKey(TypedDict, total=False): + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will not work. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Key for caching.""" + + +class OptionsProxyCacheMethodsSet(TypedDict, total=False): + """Caching for POST requests along with default GET and HEAD.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsProxyConnectTimeout(TypedDict, total=False): + """The time limit for establishing a connection with the origin.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 5s**. + """ + + +class OptionsProxyReadTimeout(TypedDict, total=False): + """ + The time limit for receiving a partial response from the origin. + If no response is received within this time, the connection will be closed. + + **Note:** + When used with a WebSocket connection, this option supports values only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 30s**. + """ + + +class OptionsQueryParamsBlacklist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as one object, files with other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryParamsWhitelist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as different objects, files with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryStringForwarding(TypedDict, total=False): + """ + The Query String Forwarding feature allows for the seamless transfer of parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication tokens or tracking information, are consistently passed along from the playlist manifest to the individual media segments. + This is particularly useful for maintaining continuity in security, analytics, and any other parameter-based operations across the entire media delivery workflow. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + forward_from_file_types: Required[SequenceNotStr[str]] + """ + The `forward_from_files_types` field specifies the types of playlist files from + which parameters will be extracted and forwarded. This typically includes + formats that list multiple media chunk references, such as HLS and DASH + playlists. Parameters associated with these playlist files (like query strings + or headers) will be propagated to the chunks they reference. + """ + + forward_to_file_types: Required[SequenceNotStr[str]] + """ + The field specifies the types of media chunk files to which parameters, + extracted from playlist files, will be forwarded. These refer to the actual + segments of media content that are delivered to viewers. Ensuring the correct + parameters are forwarded to these files is crucial for maintaining the integrity + of the streaming session. + """ + + forward_except_keys: SequenceNotStr[str] + """ + The `forward_except_keys` field provides a mechanism to exclude specific + parameters from being forwarded from playlist files to media chunk files. By + listing certain keys in this field, you can ensure that these parameters are + omitted during the forwarding process. This is particularly useful for + preventing sensitive or irrelevant information from being included in requests + for media chunks, thereby enhancing security and optimizing performance. + """ + + forward_only_keys: SequenceNotStr[str] + """ + The `forward_only_keys` field allows for granular control over which specific + parameters are forwarded from playlist files to media chunk files. By specifying + certain keys, only those parameters will be propagated, ensuring that only + relevant information is passed along. This is particularly useful for security + and performance optimization, as it prevents unnecessary or sensitive data from + being included in requests for media chunks. + """ + + +class OptionsRedirectHTTPToHTTPS(TypedDict, total=False): + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsRedirectHTTPSToHTTP(TypedDict, total=False): + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsReferrerACL(TypedDict, total=False): + """Controls access to the CDN resource content for specified domain names.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """ + List of domain names or wildcard domains (without protocol: `http://` or + `https://`.) + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of domain names for which access is prohibited. + - **deny** - List of IP domain names for which access is allowed. + + Examples: + + - `example.com` + - `*.example.com` + """ + + policy_type: Required[Literal["allow", "deny"]] + """Policy type. + + Possible values: + + - **allow** - Allow access to all domain names except the domain names specified + in `excepted_values` field. + - **deny** - Deny access to all domain names except the domain names specified + in `excepted_values` field. + """ + + +class OptionsRequestLimiter(TypedDict, total=False): + """Option allows to limit the amount of HTTP requests.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + rate: Required[int] + """Maximum request rate.""" + + rate_unit: Literal["r/s", "r/m"] + """Units of measurement for the `rate` field. + + Possible values: + + - **r/s** - Requests per second. + - **r/m** - Requests per minute. + + If the rate is less than one request per second, it is specified in request per + minute (r/m.) + """ + + +class OptionsResponseHeadersHidingPolicy(TypedDict, total=False): + """Hides HTTP headers from an origin server in the CDN response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted: Required[SequenceNotStr[str]] + """List of HTTP headers. + + Parameter meaning depends on the value of the `mode` field: + + - **show** - List of HTTP headers to hide from response. + - **hide** - List of HTTP headers to include in response. Other HTTP headers + will be hidden. + + The following headers are required and cannot be hidden from response: + + - `Connection` + - `Content-Length` + - `Content-Type` + - `Date` + - `Server` + """ + + mode: Required[Literal["hide", "show"]] + """How HTTP headers are hidden from the response. + + Possible values: + + - **show** - Hide only HTTP headers listed in the `excepted` field. + - **hide** - Hide all HTTP headers except headers listed in the "excepted" + field. + """ + + +class OptionsRewrite(TypedDict, total=False): + """Changes and redirects requests from the CDN to the origin. + + It operates according to the [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) configuration. + """ + + body: Required[str] + """Path for the Rewrite option. + + Example: + + - `/(.*) /media/$1` + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + flag: Literal["break", "last", "redirect", "permanent"] + """Flag for the Rewrite option. + + Possible values: + + - **last** - Stop processing the current set of `ngx_http_rewrite_module` + directives and start a search for a new location matching changed URI. + - **break** - Stop processing the current set of the Rewrite option. + - **redirect** - Return a temporary redirect with the 302 code; used when a + replacement string does not start with `http://`, `https://`, or `$scheme`. + - **permanent** - Return a permanent redirect with the 301 code. + """ + + +class OptionsSecureKey(TypedDict, total=False): + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + key: Required[Optional[str]] + """Key generated on your side that will be used for URL signing.""" + + type: Literal[0, 2] + """Type of URL signing. + + Possible types: + + - **Type 0** - Includes end user IP to secure token generation. + - **Type 2** - Excludes end user IP from secure token generation. + """ + + +class OptionsSlice(TypedDict, total=False): + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per part.) This reduces time to first byte. + + The option is based on the [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` options enabled. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsSni(TypedDict, total=False): + """ + The hostname that is added to SNI requests from CDN servers to the origin server via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not have a dedicated IP address. + If the origin server presents multiple certificates, SNI allows the origin server to know which certificate to use for the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + custom_hostname: Required[str] + """Custom SNI hostname. + + It is required if `sni_type` is set to custom. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + sni_type: Literal["dynamic", "custom"] + """SNI (Server Name Indication) type. + + Possible values: + + - **dynamic** - SNI hostname depends on `hostHeader` and `forward_host_header` + options. It has several possible combinations: + - If the `hostHeader` option is enabled and specified, SNI hostname matches the + Host header. + - If the `forward_host_header` option is enabled and has true value, SNI + hostname matches the Host header used in the request made to a CDN. + - If the `hostHeader` and `forward_host_header` options are disabled, SNI + hostname matches the primary CNAME. + - **custom** - custom SNI hostname is in use. + """ + + +class OptionsStale(TypedDict, total=False): + """Serves stale cached content in case of origin unavailability.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "error", + "http_403", + "http_404", + "http_429", + "http_500", + "http_502", + "http_503", + "http_504", + "invalid_header", + "timeout", + "updating", + ] + ] + ] + """Defines list of errors for which "Always online" option is applied.""" + + +class OptionsStaticResponseHeadersValue(TypedDict, total=False): + name: Required[str] + """HTTP Header name. + + Restrictions: + + - Maximum 128 symbols. + - Latin letters (A-Z, a-z,) numbers (0-9,) dashes, and underscores only. + """ + + value: Required[SequenceNotStr[str]] + """Header value. + + Restrictions: + + - Maximum 512 symbols. + - Letters (a-z), numbers (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ + /|\";:?.,><{}[]). + - Must start with a letter, number, asterisk or {. + - Multiple values can be added. + """ + + always: bool + """ + Defines whether the header will be added to a response from CDN regardless of + response code. + + Possible values: + + - **true** - Header will be added to a response from CDN regardless of response + code. + - **false** - Header will be added only to the following response codes: 200, + 201, 204, 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsStaticResponseHeaders(TypedDict, total=False): + """Custom HTTP Headers that a CDN server adds to a response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Iterable[OptionsStaticResponseHeadersValue]] + + +class OptionsStaticHeaders(TypedDict, total=False): + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP Headers can be specified. May contain a header with multiple values. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[object] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 128 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsStaticRequestHeaders(TypedDict, total=False): + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Dict[str, str]] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 255 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsUserAgentACL(TypedDict, total=False): + """Controls access to the content for specified User-Agents.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of User-Agents that will be allowed/denied. + + The meaning of the parameter depends on `policy_type`: + + - **allow** - List of User-Agents for which access is prohibited. + - **deny** - List of User-Agents for which access is allowed. + + You can provide exact User-Agent strings or regular expressions. Regular + expressions must start with `~` (case-sensitive) or `~*` (case-insensitive). + + Use an empty string `""` to allow/deny access when the User-Agent header is + empty. + """ + + policy_type: Required[Literal["allow", "deny"]] + """User-Agents policy type. + + Possible values: + + - **allow** - Allow access for all User-Agents except specified in + `excepted_values` field. + - **deny** - Deny access for all User-Agents except specified in + `excepted_values` field. + """ + + +class OptionsWaap(TypedDict, total=False): + """Allows to enable WAAP (Web Application and API Protection).""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsWebsockets(TypedDict, total=False): + """Enables or disables WebSockets connections to an origin server.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class Options(TypedDict, total=False): + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. + Option inherits its value from the CDN resource settings. + """ + + allowed_http_methods: Annotated[Optional[OptionsAllowedHTTPMethods], PropertyInfo(alias="allowedHttpMethods")] + """HTTP methods allowed for content requests from the CDN.""" + + bot_protection: Optional[OptionsBotProtection] + """ + Allows to prevent online services from overloading and ensure your business + workflow running smoothly. + """ + + brotli_compression: Optional[OptionsBrotliCompression] + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is + activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, + even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` + options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides + `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN + resource and want to enable `brotli_compression` in a rule, you must specify + `fetch_compressed:false` in the rule. + """ + + browser_cache_settings: Optional[OptionsBrowserCacheSettings] + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + cache_http_headers: Optional[OptionsCacheHTTPHeaders] + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + cors: Optional[OptionsCors] + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header + to a response to a browser. + """ + + country_acl: Optional[OptionsCountryACL] + """Enables control access to content for specified countries.""" + + disable_cache: Optional[OptionsDisableCache] + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + disable_proxy_force_ranges: Optional[OptionsDisableProxyForceRanges] + """Allows 206 responses regardless of the settings of an origin source.""" + + edge_cache_settings: Optional[OptionsEdgeCacheSettings] + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + fastedge: Optional[OptionsFastedge] + """ + Allows to configure FastEdge app to be called on different request/response + phases. + + Note: At least one of `on_request_headers`, `on_request_body`, + `on_response_headers`, or `on_response_body` must be specified. + """ + + fetch_compressed: Optional[OptionsFetchCompressed] + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress + your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or + `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If + you enable it in CDN resource and want to use `gzipON` and + `brotli_compression` in a rule, you have to specify + `"fetch_compressed": false` in the rule. + """ + + follow_origin_redirect: Optional[OptionsFollowOriginRedirect] + """ + Enables redirection from origin. If the origin server returns a redirect, the + option allows the CDN to pull the requested content from the origin server that + was returned in the redirect. + """ + + force_return: Optional[OptionsForceReturn] + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this + option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + forward_host_header: Optional[OptionsForwardHostHeader] + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + gzip_on: Annotated[Optional[OptionsGzipOn], PropertyInfo(alias="gzipOn")] + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` + options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in + rules. If you enable `fetch_compressed` in CDN resource and want to enable + `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + host_header: Annotated[Optional[OptionsHostHeader], PropertyInfo(alias="hostHeader")] + """ + Sets the Host header that CDN servers use when request content from an origin + server. Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + ignore_cookie: Optional[OptionsIgnoreCookie] + """ + Defines whether the files with the Set-Cookies header are cached as one file or + as different ones. + """ + + ignore_query_string: Annotated[Optional[OptionsIgnoreQueryString], PropertyInfo(alias="ignoreQueryString")] + """ + How a file with different query strings is cached: either as one object (option + is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + image_stack: Optional[OptionsImageStack] + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically + converts them to WebP or AVIF format. + """ + + ip_address_acl: Optional[OptionsIPAddressACL] + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, + you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. + [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + limit_bandwidth: Optional[OptionsLimitBandwidth] + """Allows to control the download speed per connection.""" + + proxy_cache_key: Optional[OptionsProxyCacheKey] + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache + and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will + not work. + """ + + proxy_cache_methods_set: Optional[OptionsProxyCacheMethodsSet] + """Caching for POST requests along with default GET and HEAD.""" + + proxy_connect_timeout: Optional[OptionsProxyConnectTimeout] + """The time limit for establishing a connection with the origin.""" + + proxy_read_timeout: Optional[OptionsProxyReadTimeout] + """ + The time limit for receiving a partial response from the origin. If no response + is received within this time, the connection will be closed. + + **Note:** When used with a WebSocket connection, this option supports values + only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + query_params_blacklist: Optional[OptionsQueryParamsBlacklist] + """ + Files with the specified query parameters are cached as one object, files with + other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_params_whitelist: Optional[OptionsQueryParamsWhitelist] + """ + Files with the specified query parameters are cached as different objects, files + with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_string_forwarding: Optional[OptionsQueryStringForwarding] + """ + The Query String Forwarding feature allows for the seamless transfer of + parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication + tokens or tracking information, are consistently passed along from the playlist + manifest to the individual media segments. This is particularly useful for + maintaining continuity in security, analytics, and any other parameter-based + operations across the entire media delivery workflow. + """ + + redirect_http_to_https: Optional[OptionsRedirectHTTPToHTTPS] + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + redirect_https_to_http: Optional[OptionsRedirectHTTPSToHTTP] + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + referrer_acl: Optional[OptionsReferrerACL] + """Controls access to the CDN resource content for specified domain names.""" + + request_limiter: Optional[OptionsRequestLimiter] + """Option allows to limit the amount of HTTP requests.""" + + response_headers_hiding_policy: Optional[OptionsResponseHeadersHidingPolicy] + """Hides HTTP headers from an origin server in the CDN response.""" + + rewrite: Optional[OptionsRewrite] + """Changes and redirects requests from the CDN to the origin. + + It operates according to the + [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) + configuration. + """ + + secure_key: Optional[OptionsSecureKey] + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + slice: Optional[OptionsSlice] + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per + part.) This reduces time to first byte. + + The option is based on the + [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` + options enabled. + """ + + sni: Optional[OptionsSni] + """ + The hostname that is added to SNI requests from CDN servers to the origin server + via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not + have a dedicated IP address. If the origin server presents multiple + certificates, SNI allows the origin server to know which certificate to use for + the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + stale: Optional[OptionsStale] + """Serves stale cached content in case of origin unavailability.""" + + static_response_headers: Optional[OptionsStaticResponseHeaders] + """Custom HTTP Headers that a CDN server adds to a response.""" + + static_headers: Annotated[Optional[OptionsStaticHeaders], PropertyInfo(alias="staticHeaders")] + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP + Headers can be specified. May contain a header with multiple values. + """ + + static_request_headers: Annotated[Optional[OptionsStaticRequestHeaders], PropertyInfo(alias="staticRequestHeaders")] + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + user_agent_acl: Optional[OptionsUserAgentACL] + """Controls access to the content for specified User-Agents.""" + + waap: Optional[OptionsWaap] + """Allows to enable WAAP (Web Application and API Protection).""" + + websockets: Optional[OptionsWebsockets] + """Enables or disables WebSockets connections to an origin server.""" diff --git a/src/gcore/types/cdn/rule_template_list.py b/src/gcore/types/cdn/rule_template_list.py new file mode 100644 index 00000000..7d194b4f --- /dev/null +++ b/src/gcore/types/cdn/rule_template_list.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .rule_template import RuleTemplate + +__all__ = ["RuleTemplateList"] + +RuleTemplateList: TypeAlias = List[RuleTemplate] diff --git a/src/gcore/types/cdn/rule_template_replace_params.py b/src/gcore/types/cdn/rule_template_replace_params.py new file mode 100644 index 00000000..2fe52fdc --- /dev/null +++ b/src/gcore/types/cdn/rule_template_replace_params.py @@ -0,0 +1,1924 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable, Optional +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = [ + "RuleTemplateReplaceParams", + "Options", + "OptionsAllowedHTTPMethods", + "OptionsBotProtection", + "OptionsBotProtectionBotChallenge", + "OptionsBrotliCompression", + "OptionsBrowserCacheSettings", + "OptionsCacheHTTPHeaders", + "OptionsCors", + "OptionsCountryACL", + "OptionsDisableCache", + "OptionsDisableProxyForceRanges", + "OptionsEdgeCacheSettings", + "OptionsFastedge", + "OptionsFastedgeOnRequestBody", + "OptionsFastedgeOnRequestHeaders", + "OptionsFastedgeOnResponseBody", + "OptionsFastedgeOnResponseHeaders", + "OptionsFetchCompressed", + "OptionsFollowOriginRedirect", + "OptionsForceReturn", + "OptionsForceReturnTimeInterval", + "OptionsForwardHostHeader", + "OptionsGzipOn", + "OptionsHostHeader", + "OptionsIgnoreCookie", + "OptionsIgnoreQueryString", + "OptionsImageStack", + "OptionsIPAddressACL", + "OptionsLimitBandwidth", + "OptionsProxyCacheKey", + "OptionsProxyCacheMethodsSet", + "OptionsProxyConnectTimeout", + "OptionsProxyReadTimeout", + "OptionsQueryParamsBlacklist", + "OptionsQueryParamsWhitelist", + "OptionsQueryStringForwarding", + "OptionsRedirectHTTPToHTTPS", + "OptionsRedirectHTTPSToHTTP", + "OptionsReferrerACL", + "OptionsRequestLimiter", + "OptionsResponseHeadersHidingPolicy", + "OptionsRewrite", + "OptionsSecureKey", + "OptionsSlice", + "OptionsSni", + "OptionsStale", + "OptionsStaticResponseHeaders", + "OptionsStaticResponseHeadersValue", + "OptionsStaticHeaders", + "OptionsStaticRequestHeaders", + "OptionsUserAgentACL", + "OptionsWaap", + "OptionsWebsockets", +] + + +class RuleTemplateReplaceParams(TypedDict, total=False): + rule: Required[str] + """Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + """ + + rule_type: Required[Annotated[int, PropertyInfo(alias="ruleType")]] + """Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + """ + + name: str + """Rule template name.""" + + options: Options + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + """ + + override_origin_protocol: Annotated[ + Optional[Literal["HTTPS", "HTTP", "MATCH"]], PropertyInfo(alias="overrideOriginProtocol") + ] + """ + Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + """ + + weight: int + """Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + """ + + +class OptionsAllowedHTTPMethods(TypedDict, total=False): + """HTTP methods allowed for content requests from the CDN.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[List[Literal["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]]] + + +class OptionsBotProtectionBotChallenge(TypedDict, total=False): + """Controls the bot challenge module state.""" + + enabled: bool + """Possible values: + + - **true** - Bot challenge is enabled. + - **false** - Bot challenge is disabled. + """ + + +class OptionsBotProtection(TypedDict, total=False): + """ + Allows to prevent online services from overloading and ensure your business workflow running smoothly. + """ + + bot_challenge: Required[OptionsBotProtectionBotChallenge] + """Controls the bot challenge module state.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsBrotliCompression(TypedDict, total=False): + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN resource and want to enable `brotli_compression` in a rule, you must specify `fetch_compressed:false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "application/javascript", + "application/json", + "application/vnd.ms-fontobject", + "application/wasm", + "application/x-font-ttf", + "application/x-javascript", + "application/xml", + "application/xml+rss", + "image/svg+xml", + "image/x-icon", + "text/css", + "text/html", + "text/javascript", + "text/plain", + "text/xml", + ] + ] + ] + """Allows to select the content types you want to compress. + + `text/html` is a mandatory content type. + """ + + +class OptionsBrowserCacheSettings(TypedDict, total=False): + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Set the cache expiration time to '0s' to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsCacheHTTPHeaders(TypedDict, total=False): + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + + +class OptionsCors(TypedDict, total=False): + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header to a response to a browser. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """Value of the Access-Control-Allow-Origin header. + + Possible values: + + - **Adds \\** as the Access-Control-Allow-Origin header value** - Content will be + uploaded for requests from any domain. `"value": ["*"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value if the + origin matches one of the listed domains** - Content will be uploaded only for + requests from the domains specified in the field. + `"value": ["domain.com", "second.dom.com"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value** - + Content will be uploaded for requests from any domain, and the domain from + which the request was sent will be added to the "Access-Control-Allow-Origin" + header in the response. `"value": ["$http_origin"]` + """ + + always: bool + """ + Defines whether the Access-Control-Allow-Origin header should be added to a + response from CDN regardless of response code. + + Possible values: + + - **true** - Header will be added to a response regardless of response code. + - **false** - Header will only be added to responses with codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsCountryACL(TypedDict, total=False): + """Enables control access to content for specified countries.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of countries according to ISO-3166-1. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of countries for which access is prohibited. + - **deny** - List of countries for which access is allowed. + """ + + policy_type: Required[Literal["allow", "deny"]] + """Defines the type of CDN resource access policy. + + Possible values: + + - **allow** - Access is allowed for all the countries except for those specified + in `excepted_values` field. + - **deny** - Access is denied for all the countries except for those specified + in `excepted_values` field. + """ + + +class OptionsDisableCache(TypedDict, total=False): + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - content caching is disabled. + - **false** - content caching is enabled. + """ + + +class OptionsDisableProxyForceRanges(TypedDict, total=False): + """Allows 206 responses regardless of the settings of an origin source.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsEdgeCacheSettings(TypedDict, total=False): + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + custom_values: Dict[str, str] + """ + A MAP object representing the caching time in seconds for a response with a + specific response code. + + These settings have a higher priority than the `value` field. + + - Use `any` key to specify caching time for all response codes. + - Use `0s` value to disable caching for a specific response code. + """ + + default: str + """Enables content caching according to the origin cache settings. + + The value is applied to the following response codes 200, 201, 204, 206, 301, + 302, 303, 304, 307, 308, if an origin server does not have caching HTTP headers. + + Responses with other codes will not be cached. + + The maximum duration is any equivalent to `1y`. + """ + + value: str + """Caching time. + + The value is applied to the following response codes: 200, 206, 301, 302. + Responses with codes 4xx, 5xx will not be cached. + + Use `0s` to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsFastedgeOnRequestBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request body as soon as CDN receives incoming HTTP request. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnRequestHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response body before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response headers before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedge(TypedDict, total=False): + """ + Allows to configure FastEdge app to be called on different request/response phases. + + Note: At least one of `on_request_headers`, `on_request_body`, `on_response_headers`, or `on_response_body` must be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + on_request_body: OptionsFastedgeOnRequestBody + """ + Allows to configure FastEdge application that will be called to handle request + body as soon as CDN receives incoming HTTP request. + """ + + on_request_headers: OptionsFastedgeOnRequestHeaders + """ + Allows to configure FastEdge application that will be called to handle request + headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + on_response_body: OptionsFastedgeOnResponseBody + """ + Allows to configure FastEdge application that will be called to handle response + body before CDN sends the HTTP response. + """ + + on_response_headers: OptionsFastedgeOnResponseHeaders + """ + Allows to configure FastEdge application that will be called to handle response + headers before CDN sends the HTTP response. + """ + + +class OptionsFetchCompressed(TypedDict, total=False): + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If you enable it in CDN resource and want to use `gzipON` and `brotli_compression` in a rule, you have to specify `"fetch_compressed": false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsFollowOriginRedirect(TypedDict, total=False): + """ + Enables redirection from origin. + If the origin server returns a redirect, the option allows the CDN to pull the requested content from the origin server that was returned in the redirect. + """ + + codes: Required[Iterable[Literal[301, 302, 303, 307, 308]]] + """Redirect status code that the origin server returns. + + To serve up to date content to end users, you will need to purge the cache after + managing the option. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsForceReturnTimeInterval(TypedDict, total=False): + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + end_time: Required[str] + """Time until which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + start_time: Required[str] + """Time from which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + time_zone: str + """Time zone used to calculate time.""" + + +class OptionsForceReturn(TypedDict, total=False): + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + body: Required[str] + """URL for redirection or text.""" + + code: Required[int] + """Status code value.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + time_interval: Optional[OptionsForceReturnTimeInterval] + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + +class OptionsForwardHostHeader(TypedDict, total=False): + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsGzipOn(TypedDict, total=False): + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in rules. If you enable `fetch_compressed` in CDN resource and want to enable `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsHostHeader(TypedDict, total=False): + """ + Sets the Host header that CDN servers use when request content from an origin server. + Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Host Header value.""" + + +class OptionsIgnoreCookie(TypedDict, total=False): + """ + Defines whether the files with the Set-Cookies header are cached as one file or as different ones. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled, files with cookies are cached as one file. + - **false** - Option is disabled, files with cookies are cached as different + files. + """ + + +class OptionsIgnoreQueryString(TypedDict, total=False): + """ + How a file with different query strings is cached: either as one object (option is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsImageStack(TypedDict, total=False): + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically converts them to WebP or AVIF format. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + avif_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to AVI format.""" + + png_lossless: bool + """Enables or disables compression without quality loss for PNG format.""" + + quality: int + """Defines quality settings for JPG and PNG images. + + The higher the value, the better the image quality, and the larger the file size + after conversion. + """ + + webp_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to WebP format.""" + + +class OptionsIPAddressACL(TypedDict, total=False): + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of IP addresses with a subnet mask. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of IP addresses for which access is prohibited. + - **deny** - List of IP addresses for which access is allowed. + + Examples: + + - `192.168.3.2/32` + - `2a03:d000:2980:7::8/128` + """ + + policy_type: Required[Literal["allow", "deny"]] + """IP access policy type. + + Possible values: + + - **allow** - Allow access to all IPs except IPs specified in "excepted_values" + field. + - **deny** - Deny access to all IPs except IPs specified in "excepted_values" + field. + """ + + +class OptionsLimitBandwidth(TypedDict, total=False): + """Allows to control the download speed per connection.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + limit_type: Required[Literal["static", "dynamic"]] + """Method of controlling the download speed per connection. + + Possible values: + + - **static** - Use speed and buffer fields to set the download speed limit. + - **dynamic** - Use query strings **speed** and **buffer** to set the download + speed limit. + + For example, when requesting content at the link + + ``` + http://cdn.example.com/video.mp4?speed=50k&buffer=500k + ``` + + the download speed will be limited to 50kB/s after 500 kB. + """ + + buffer: int + """Amount of downloaded data after which the user will be rate limited.""" + + speed: int + """Maximum download speed per connection.""" + + +class OptionsProxyCacheKey(TypedDict, total=False): + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will not work. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Key for caching.""" + + +class OptionsProxyCacheMethodsSet(TypedDict, total=False): + """Caching for POST requests along with default GET and HEAD.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsProxyConnectTimeout(TypedDict, total=False): + """The time limit for establishing a connection with the origin.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 5s**. + """ + + +class OptionsProxyReadTimeout(TypedDict, total=False): + """ + The time limit for receiving a partial response from the origin. + If no response is received within this time, the connection will be closed. + + **Note:** + When used with a WebSocket connection, this option supports values only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 30s**. + """ + + +class OptionsQueryParamsBlacklist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as one object, files with other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryParamsWhitelist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as different objects, files with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryStringForwarding(TypedDict, total=False): + """ + The Query String Forwarding feature allows for the seamless transfer of parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication tokens or tracking information, are consistently passed along from the playlist manifest to the individual media segments. + This is particularly useful for maintaining continuity in security, analytics, and any other parameter-based operations across the entire media delivery workflow. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + forward_from_file_types: Required[SequenceNotStr[str]] + """ + The `forward_from_files_types` field specifies the types of playlist files from + which parameters will be extracted and forwarded. This typically includes + formats that list multiple media chunk references, such as HLS and DASH + playlists. Parameters associated with these playlist files (like query strings + or headers) will be propagated to the chunks they reference. + """ + + forward_to_file_types: Required[SequenceNotStr[str]] + """ + The field specifies the types of media chunk files to which parameters, + extracted from playlist files, will be forwarded. These refer to the actual + segments of media content that are delivered to viewers. Ensuring the correct + parameters are forwarded to these files is crucial for maintaining the integrity + of the streaming session. + """ + + forward_except_keys: SequenceNotStr[str] + """ + The `forward_except_keys` field provides a mechanism to exclude specific + parameters from being forwarded from playlist files to media chunk files. By + listing certain keys in this field, you can ensure that these parameters are + omitted during the forwarding process. This is particularly useful for + preventing sensitive or irrelevant information from being included in requests + for media chunks, thereby enhancing security and optimizing performance. + """ + + forward_only_keys: SequenceNotStr[str] + """ + The `forward_only_keys` field allows for granular control over which specific + parameters are forwarded from playlist files to media chunk files. By specifying + certain keys, only those parameters will be propagated, ensuring that only + relevant information is passed along. This is particularly useful for security + and performance optimization, as it prevents unnecessary or sensitive data from + being included in requests for media chunks. + """ + + +class OptionsRedirectHTTPToHTTPS(TypedDict, total=False): + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsRedirectHTTPSToHTTP(TypedDict, total=False): + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsReferrerACL(TypedDict, total=False): + """Controls access to the CDN resource content for specified domain names.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """ + List of domain names or wildcard domains (without protocol: `http://` or + `https://`.) + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of domain names for which access is prohibited. + - **deny** - List of IP domain names for which access is allowed. + + Examples: + + - `example.com` + - `*.example.com` + """ + + policy_type: Required[Literal["allow", "deny"]] + """Policy type. + + Possible values: + + - **allow** - Allow access to all domain names except the domain names specified + in `excepted_values` field. + - **deny** - Deny access to all domain names except the domain names specified + in `excepted_values` field. + """ + + +class OptionsRequestLimiter(TypedDict, total=False): + """Option allows to limit the amount of HTTP requests.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + rate: Required[int] + """Maximum request rate.""" + + rate_unit: Literal["r/s", "r/m"] + """Units of measurement for the `rate` field. + + Possible values: + + - **r/s** - Requests per second. + - **r/m** - Requests per minute. + + If the rate is less than one request per second, it is specified in request per + minute (r/m.) + """ + + +class OptionsResponseHeadersHidingPolicy(TypedDict, total=False): + """Hides HTTP headers from an origin server in the CDN response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted: Required[SequenceNotStr[str]] + """List of HTTP headers. + + Parameter meaning depends on the value of the `mode` field: + + - **show** - List of HTTP headers to hide from response. + - **hide** - List of HTTP headers to include in response. Other HTTP headers + will be hidden. + + The following headers are required and cannot be hidden from response: + + - `Connection` + - `Content-Length` + - `Content-Type` + - `Date` + - `Server` + """ + + mode: Required[Literal["hide", "show"]] + """How HTTP headers are hidden from the response. + + Possible values: + + - **show** - Hide only HTTP headers listed in the `excepted` field. + - **hide** - Hide all HTTP headers except headers listed in the "excepted" + field. + """ + + +class OptionsRewrite(TypedDict, total=False): + """Changes and redirects requests from the CDN to the origin. + + It operates according to the [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) configuration. + """ + + body: Required[str] + """Path for the Rewrite option. + + Example: + + - `/(.*) /media/$1` + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + flag: Literal["break", "last", "redirect", "permanent"] + """Flag for the Rewrite option. + + Possible values: + + - **last** - Stop processing the current set of `ngx_http_rewrite_module` + directives and start a search for a new location matching changed URI. + - **break** - Stop processing the current set of the Rewrite option. + - **redirect** - Return a temporary redirect with the 302 code; used when a + replacement string does not start with `http://`, `https://`, or `$scheme`. + - **permanent** - Return a permanent redirect with the 301 code. + """ + + +class OptionsSecureKey(TypedDict, total=False): + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + key: Required[Optional[str]] + """Key generated on your side that will be used for URL signing.""" + + type: Literal[0, 2] + """Type of URL signing. + + Possible types: + + - **Type 0** - Includes end user IP to secure token generation. + - **Type 2** - Excludes end user IP from secure token generation. + """ + + +class OptionsSlice(TypedDict, total=False): + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per part.) This reduces time to first byte. + + The option is based on the [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` options enabled. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsSni(TypedDict, total=False): + """ + The hostname that is added to SNI requests from CDN servers to the origin server via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not have a dedicated IP address. + If the origin server presents multiple certificates, SNI allows the origin server to know which certificate to use for the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + custom_hostname: Required[str] + """Custom SNI hostname. + + It is required if `sni_type` is set to custom. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + sni_type: Literal["dynamic", "custom"] + """SNI (Server Name Indication) type. + + Possible values: + + - **dynamic** - SNI hostname depends on `hostHeader` and `forward_host_header` + options. It has several possible combinations: + - If the `hostHeader` option is enabled and specified, SNI hostname matches the + Host header. + - If the `forward_host_header` option is enabled and has true value, SNI + hostname matches the Host header used in the request made to a CDN. + - If the `hostHeader` and `forward_host_header` options are disabled, SNI + hostname matches the primary CNAME. + - **custom** - custom SNI hostname is in use. + """ + + +class OptionsStale(TypedDict, total=False): + """Serves stale cached content in case of origin unavailability.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "error", + "http_403", + "http_404", + "http_429", + "http_500", + "http_502", + "http_503", + "http_504", + "invalid_header", + "timeout", + "updating", + ] + ] + ] + """Defines list of errors for which "Always online" option is applied.""" + + +class OptionsStaticResponseHeadersValue(TypedDict, total=False): + name: Required[str] + """HTTP Header name. + + Restrictions: + + - Maximum 128 symbols. + - Latin letters (A-Z, a-z,) numbers (0-9,) dashes, and underscores only. + """ + + value: Required[SequenceNotStr[str]] + """Header value. + + Restrictions: + + - Maximum 512 symbols. + - Letters (a-z), numbers (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ + /|\";:?.,><{}[]). + - Must start with a letter, number, asterisk or {. + - Multiple values can be added. + """ + + always: bool + """ + Defines whether the header will be added to a response from CDN regardless of + response code. + + Possible values: + + - **true** - Header will be added to a response from CDN regardless of response + code. + - **false** - Header will be added only to the following response codes: 200, + 201, 204, 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsStaticResponseHeaders(TypedDict, total=False): + """Custom HTTP Headers that a CDN server adds to a response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Iterable[OptionsStaticResponseHeadersValue]] + + +class OptionsStaticHeaders(TypedDict, total=False): + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP Headers can be specified. May contain a header with multiple values. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[object] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 128 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsStaticRequestHeaders(TypedDict, total=False): + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Dict[str, str]] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 255 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsUserAgentACL(TypedDict, total=False): + """Controls access to the content for specified User-Agents.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of User-Agents that will be allowed/denied. + + The meaning of the parameter depends on `policy_type`: + + - **allow** - List of User-Agents for which access is prohibited. + - **deny** - List of User-Agents for which access is allowed. + + You can provide exact User-Agent strings or regular expressions. Regular + expressions must start with `~` (case-sensitive) or `~*` (case-insensitive). + + Use an empty string `""` to allow/deny access when the User-Agent header is + empty. + """ + + policy_type: Required[Literal["allow", "deny"]] + """User-Agents policy type. + + Possible values: + + - **allow** - Allow access for all User-Agents except specified in + `excepted_values` field. + - **deny** - Deny access for all User-Agents except specified in + `excepted_values` field. + """ + + +class OptionsWaap(TypedDict, total=False): + """Allows to enable WAAP (Web Application and API Protection).""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsWebsockets(TypedDict, total=False): + """Enables or disables WebSockets connections to an origin server.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class Options(TypedDict, total=False): + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. + Option inherits its value from the CDN resource settings. + """ + + allowed_http_methods: Annotated[Optional[OptionsAllowedHTTPMethods], PropertyInfo(alias="allowedHttpMethods")] + """HTTP methods allowed for content requests from the CDN.""" + + bot_protection: Optional[OptionsBotProtection] + """ + Allows to prevent online services from overloading and ensure your business + workflow running smoothly. + """ + + brotli_compression: Optional[OptionsBrotliCompression] + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is + activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, + even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` + options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides + `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN + resource and want to enable `brotli_compression` in a rule, you must specify + `fetch_compressed:false` in the rule. + """ + + browser_cache_settings: Optional[OptionsBrowserCacheSettings] + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + cache_http_headers: Optional[OptionsCacheHTTPHeaders] + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + cors: Optional[OptionsCors] + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header + to a response to a browser. + """ + + country_acl: Optional[OptionsCountryACL] + """Enables control access to content for specified countries.""" + + disable_cache: Optional[OptionsDisableCache] + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + disable_proxy_force_ranges: Optional[OptionsDisableProxyForceRanges] + """Allows 206 responses regardless of the settings of an origin source.""" + + edge_cache_settings: Optional[OptionsEdgeCacheSettings] + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + fastedge: Optional[OptionsFastedge] + """ + Allows to configure FastEdge app to be called on different request/response + phases. + + Note: At least one of `on_request_headers`, `on_request_body`, + `on_response_headers`, or `on_response_body` must be specified. + """ + + fetch_compressed: Optional[OptionsFetchCompressed] + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress + your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or + `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If + you enable it in CDN resource and want to use `gzipON` and + `brotli_compression` in a rule, you have to specify + `"fetch_compressed": false` in the rule. + """ + + follow_origin_redirect: Optional[OptionsFollowOriginRedirect] + """ + Enables redirection from origin. If the origin server returns a redirect, the + option allows the CDN to pull the requested content from the origin server that + was returned in the redirect. + """ + + force_return: Optional[OptionsForceReturn] + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this + option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + forward_host_header: Optional[OptionsForwardHostHeader] + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + gzip_on: Annotated[Optional[OptionsGzipOn], PropertyInfo(alias="gzipOn")] + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` + options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in + rules. If you enable `fetch_compressed` in CDN resource and want to enable + `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + host_header: Annotated[Optional[OptionsHostHeader], PropertyInfo(alias="hostHeader")] + """ + Sets the Host header that CDN servers use when request content from an origin + server. Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + ignore_cookie: Optional[OptionsIgnoreCookie] + """ + Defines whether the files with the Set-Cookies header are cached as one file or + as different ones. + """ + + ignore_query_string: Annotated[Optional[OptionsIgnoreQueryString], PropertyInfo(alias="ignoreQueryString")] + """ + How a file with different query strings is cached: either as one object (option + is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + image_stack: Optional[OptionsImageStack] + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically + converts them to WebP or AVIF format. + """ + + ip_address_acl: Optional[OptionsIPAddressACL] + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, + you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. + [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + limit_bandwidth: Optional[OptionsLimitBandwidth] + """Allows to control the download speed per connection.""" + + proxy_cache_key: Optional[OptionsProxyCacheKey] + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache + and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will + not work. + """ + + proxy_cache_methods_set: Optional[OptionsProxyCacheMethodsSet] + """Caching for POST requests along with default GET and HEAD.""" + + proxy_connect_timeout: Optional[OptionsProxyConnectTimeout] + """The time limit for establishing a connection with the origin.""" + + proxy_read_timeout: Optional[OptionsProxyReadTimeout] + """ + The time limit for receiving a partial response from the origin. If no response + is received within this time, the connection will be closed. + + **Note:** When used with a WebSocket connection, this option supports values + only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + query_params_blacklist: Optional[OptionsQueryParamsBlacklist] + """ + Files with the specified query parameters are cached as one object, files with + other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_params_whitelist: Optional[OptionsQueryParamsWhitelist] + """ + Files with the specified query parameters are cached as different objects, files + with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_string_forwarding: Optional[OptionsQueryStringForwarding] + """ + The Query String Forwarding feature allows for the seamless transfer of + parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication + tokens or tracking information, are consistently passed along from the playlist + manifest to the individual media segments. This is particularly useful for + maintaining continuity in security, analytics, and any other parameter-based + operations across the entire media delivery workflow. + """ + + redirect_http_to_https: Optional[OptionsRedirectHTTPToHTTPS] + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + redirect_https_to_http: Optional[OptionsRedirectHTTPSToHTTP] + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + referrer_acl: Optional[OptionsReferrerACL] + """Controls access to the CDN resource content for specified domain names.""" + + request_limiter: Optional[OptionsRequestLimiter] + """Option allows to limit the amount of HTTP requests.""" + + response_headers_hiding_policy: Optional[OptionsResponseHeadersHidingPolicy] + """Hides HTTP headers from an origin server in the CDN response.""" + + rewrite: Optional[OptionsRewrite] + """Changes and redirects requests from the CDN to the origin. + + It operates according to the + [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) + configuration. + """ + + secure_key: Optional[OptionsSecureKey] + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + slice: Optional[OptionsSlice] + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per + part.) This reduces time to first byte. + + The option is based on the + [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` + options enabled. + """ + + sni: Optional[OptionsSni] + """ + The hostname that is added to SNI requests from CDN servers to the origin server + via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not + have a dedicated IP address. If the origin server presents multiple + certificates, SNI allows the origin server to know which certificate to use for + the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + stale: Optional[OptionsStale] + """Serves stale cached content in case of origin unavailability.""" + + static_response_headers: Optional[OptionsStaticResponseHeaders] + """Custom HTTP Headers that a CDN server adds to a response.""" + + static_headers: Annotated[Optional[OptionsStaticHeaders], PropertyInfo(alias="staticHeaders")] + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP + Headers can be specified. May contain a header with multiple values. + """ + + static_request_headers: Annotated[Optional[OptionsStaticRequestHeaders], PropertyInfo(alias="staticRequestHeaders")] + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + user_agent_acl: Optional[OptionsUserAgentACL] + """Controls access to the content for specified User-Agents.""" + + waap: Optional[OptionsWaap] + """Allows to enable WAAP (Web Application and API Protection).""" + + websockets: Optional[OptionsWebsockets] + """Enables or disables WebSockets connections to an origin server.""" diff --git a/src/gcore/types/cdn/rule_template_update_params.py b/src/gcore/types/cdn/rule_template_update_params.py new file mode 100644 index 00000000..cccc6bc0 --- /dev/null +++ b/src/gcore/types/cdn/rule_template_update_params.py @@ -0,0 +1,1924 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable, Optional +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = [ + "RuleTemplateUpdateParams", + "Options", + "OptionsAllowedHTTPMethods", + "OptionsBotProtection", + "OptionsBotProtectionBotChallenge", + "OptionsBrotliCompression", + "OptionsBrowserCacheSettings", + "OptionsCacheHTTPHeaders", + "OptionsCors", + "OptionsCountryACL", + "OptionsDisableCache", + "OptionsDisableProxyForceRanges", + "OptionsEdgeCacheSettings", + "OptionsFastedge", + "OptionsFastedgeOnRequestBody", + "OptionsFastedgeOnRequestHeaders", + "OptionsFastedgeOnResponseBody", + "OptionsFastedgeOnResponseHeaders", + "OptionsFetchCompressed", + "OptionsFollowOriginRedirect", + "OptionsForceReturn", + "OptionsForceReturnTimeInterval", + "OptionsForwardHostHeader", + "OptionsGzipOn", + "OptionsHostHeader", + "OptionsIgnoreCookie", + "OptionsIgnoreQueryString", + "OptionsImageStack", + "OptionsIPAddressACL", + "OptionsLimitBandwidth", + "OptionsProxyCacheKey", + "OptionsProxyCacheMethodsSet", + "OptionsProxyConnectTimeout", + "OptionsProxyReadTimeout", + "OptionsQueryParamsBlacklist", + "OptionsQueryParamsWhitelist", + "OptionsQueryStringForwarding", + "OptionsRedirectHTTPToHTTPS", + "OptionsRedirectHTTPSToHTTP", + "OptionsReferrerACL", + "OptionsRequestLimiter", + "OptionsResponseHeadersHidingPolicy", + "OptionsRewrite", + "OptionsSecureKey", + "OptionsSlice", + "OptionsSni", + "OptionsStale", + "OptionsStaticResponseHeaders", + "OptionsStaticResponseHeadersValue", + "OptionsStaticHeaders", + "OptionsStaticRequestHeaders", + "OptionsUserAgentACL", + "OptionsWaap", + "OptionsWebsockets", +] + + +class RuleTemplateUpdateParams(TypedDict, total=False): + name: str + """Rule template name.""" + + options: Options + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. Option inherits its + value from the CDN resource settings. + """ + + override_origin_protocol: Annotated[ + Optional[Literal["HTTPS", "HTTP", "MATCH"]], PropertyInfo(alias="overrideOriginProtocol") + ] + """ + Sets a protocol other than the one specified in the CDN resource settings to + connect to the origin. + + Possible values: + + - **HTTPS** - CDN servers connect to origin via HTTPS protocol. + - **HTTP** - CDN servers connect to origin via HTTP protocol. + - **MATCH** - Connection protocol is chosen automatically; in this case, content + on origin source should be available for the CDN both through HTTP and HTTPS + protocols. + - **null** - `originProtocol` setting is inherited from the CDN resource + settings. + """ + + rule: str + """Path to the file or folder for which the rule will be applied. + + The rule is applied if the requested URI matches the rule path. + + We add a leading forward slash to any rule path. Specify a path without a + forward slash. + """ + + rule_type: Annotated[int, PropertyInfo(alias="ruleType")] + """Rule type. + + Possible values: + + - **Type 0** - Regular expression. Must start with '^/' or '/'. + - **Type 1** - Regular expression. Note that for this rule type we automatically + add / to each rule pattern before your regular expression. This type is + **legacy**, please use Type 0. + """ + + weight: int + """Rule execution order: from lowest (1) to highest. + + If requested URI matches multiple rules, the one higher in the order of the + rules will be applied. + """ + + +class OptionsAllowedHTTPMethods(TypedDict, total=False): + """HTTP methods allowed for content requests from the CDN.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[List[Literal["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]]] + + +class OptionsBotProtectionBotChallenge(TypedDict, total=False): + """Controls the bot challenge module state.""" + + enabled: bool + """Possible values: + + - **true** - Bot challenge is enabled. + - **false** - Bot challenge is disabled. + """ + + +class OptionsBotProtection(TypedDict, total=False): + """ + Allows to prevent online services from overloading and ensure your business workflow running smoothly. + """ + + bot_challenge: Required[OptionsBotProtectionBotChallenge] + """Controls the bot challenge module state.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsBrotliCompression(TypedDict, total=False): + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN resource and want to enable `brotli_compression` in a rule, you must specify `fetch_compressed:false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "application/javascript", + "application/json", + "application/vnd.ms-fontobject", + "application/wasm", + "application/x-font-ttf", + "application/x-javascript", + "application/xml", + "application/xml+rss", + "image/svg+xml", + "image/x-icon", + "text/css", + "text/html", + "text/javascript", + "text/plain", + "text/xml", + ] + ] + ] + """Allows to select the content types you want to compress. + + `text/html` is a mandatory content type. + """ + + +class OptionsBrowserCacheSettings(TypedDict, total=False): + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Set the cache expiration time to '0s' to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsCacheHTTPHeaders(TypedDict, total=False): + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + + +class OptionsCors(TypedDict, total=False): + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header to a response to a browser. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """Value of the Access-Control-Allow-Origin header. + + Possible values: + + - **Adds \\** as the Access-Control-Allow-Origin header value** - Content will be + uploaded for requests from any domain. `"value": ["*"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value if the + origin matches one of the listed domains** - Content will be uploaded only for + requests from the domains specified in the field. + `"value": ["domain.com", "second.dom.com"]` + - **Adds "$http_origin" as the Access-Control-Allow-Origin header value** - + Content will be uploaded for requests from any domain, and the domain from + which the request was sent will be added to the "Access-Control-Allow-Origin" + header in the response. `"value": ["$http_origin"]` + """ + + always: bool + """ + Defines whether the Access-Control-Allow-Origin header should be added to a + response from CDN regardless of response code. + + Possible values: + + - **true** - Header will be added to a response regardless of response code. + - **false** - Header will only be added to responses with codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsCountryACL(TypedDict, total=False): + """Enables control access to content for specified countries.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of countries according to ISO-3166-1. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of countries for which access is prohibited. + - **deny** - List of countries for which access is allowed. + """ + + policy_type: Required[Literal["allow", "deny"]] + """Defines the type of CDN resource access policy. + + Possible values: + + - **allow** - Access is allowed for all the countries except for those specified + in `excepted_values` field. + - **deny** - Access is denied for all the countries except for those specified + in `excepted_values` field. + """ + + +class OptionsDisableCache(TypedDict, total=False): + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - content caching is disabled. + - **false** - content caching is enabled. + """ + + +class OptionsDisableProxyForceRanges(TypedDict, total=False): + """Allows 206 responses regardless of the settings of an origin source.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsEdgeCacheSettings(TypedDict, total=False): + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + custom_values: Dict[str, str] + """ + A MAP object representing the caching time in seconds for a response with a + specific response code. + + These settings have a higher priority than the `value` field. + + - Use `any` key to specify caching time for all response codes. + - Use `0s` value to disable caching for a specific response code. + """ + + default: str + """Enables content caching according to the origin cache settings. + + The value is applied to the following response codes 200, 201, 204, 206, 301, + 302, 303, 304, 307, 308, if an origin server does not have caching HTTP headers. + + Responses with other codes will not be cached. + + The maximum duration is any equivalent to `1y`. + """ + + value: str + """Caching time. + + The value is applied to the following response codes: 200, 206, 301, 302. + Responses with codes 4xx, 5xx will not be cached. + + Use `0s` to disable caching. + + The maximum duration is any equivalent to `1y`. + """ + + +class OptionsFastedgeOnRequestBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request body as soon as CDN receives incoming HTTP request. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnRequestHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle request headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseBody(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response body before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedgeOnResponseHeaders(TypedDict, total=False): + """ + Allows to configure FastEdge application that will be called to handle response headers before CDN sends the HTTP response. + """ + + app_id: Required[str] + """The ID of the application in FastEdge.""" + + enabled: bool + """ + Determines if the FastEdge application should be called whenever HTTP request + headers are received. + """ + + execute_on_edge: bool + """Determines if the request should be executed at the edge nodes.""" + + execute_on_shield: bool + """Determines if the request should be executed at the shield nodes.""" + + interrupt_on_error: bool + """Determines if the request execution should be interrupted when an error occurs.""" + + +class OptionsFastedge(TypedDict, total=False): + """ + Allows to configure FastEdge app to be called on different request/response phases. + + Note: At least one of `on_request_headers`, `on_request_body`, `on_response_headers`, or `on_response_body` must be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + on_request_body: OptionsFastedgeOnRequestBody + """ + Allows to configure FastEdge application that will be called to handle request + body as soon as CDN receives incoming HTTP request. + """ + + on_request_headers: OptionsFastedgeOnRequestHeaders + """ + Allows to configure FastEdge application that will be called to handle request + headers as soon as CDN receives incoming HTTP request, **before cache**. + """ + + on_response_body: OptionsFastedgeOnResponseBody + """ + Allows to configure FastEdge application that will be called to handle response + body before CDN sends the HTTP response. + """ + + on_response_headers: OptionsFastedgeOnResponseHeaders + """ + Allows to configure FastEdge application that will be called to handle response + headers before CDN sends the HTTP response. + """ + + +class OptionsFetchCompressed(TypedDict, total=False): + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If you enable it in CDN resource and want to use `gzipON` and `brotli_compression` in a rule, you have to specify `"fetch_compressed": false` in the rule. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsFollowOriginRedirect(TypedDict, total=False): + """ + Enables redirection from origin. + If the origin server returns a redirect, the option allows the CDN to pull the requested content from the origin server that was returned in the redirect. + """ + + codes: Required[Iterable[Literal[301, 302, 303, 307, 308]]] + """Redirect status code that the origin server returns. + + To serve up to date content to end users, you will need to purge the cache after + managing the option. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsForceReturnTimeInterval(TypedDict, total=False): + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + end_time: Required[str] + """Time until which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + start_time: Required[str] + """Time from which a custom HTTP response code should be applied. + + Indicated in 24-hour format. + """ + + time_zone: str + """Time zone used to calculate time.""" + + +class OptionsForceReturn(TypedDict, total=False): + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + body: Required[str] + """URL for redirection or text.""" + + code: Required[int] + """Status code value.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + time_interval: Optional[OptionsForceReturnTimeInterval] + """Controls the time at which a custom HTTP response code should be applied. + + By default, a custom HTTP response code is applied at any time. + """ + + +class OptionsForwardHostHeader(TypedDict, total=False): + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsGzipOn(TypedDict, total=False): + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in rules. If you enable `fetch_compressed` in CDN resource and want to enable `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsHostHeader(TypedDict, total=False): + """ + Sets the Host header that CDN servers use when request content from an origin server. + Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Host Header value.""" + + +class OptionsIgnoreCookie(TypedDict, total=False): + """ + Defines whether the files with the Set-Cookies header are cached as one file or as different ones. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled, files with cookies are cached as one file. + - **false** - Option is disabled, files with cookies are cached as different + files. + """ + + +class OptionsIgnoreQueryString(TypedDict, total=False): + """ + How a file with different query strings is cached: either as one object (option is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsImageStack(TypedDict, total=False): + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically converts them to WebP or AVIF format. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + avif_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to AVI format.""" + + png_lossless: bool + """Enables or disables compression without quality loss for PNG format.""" + + quality: int + """Defines quality settings for JPG and PNG images. + + The higher the value, the better the image quality, and the larger the file size + after conversion. + """ + + webp_enabled: bool + """Enables or disables automatic conversion of JPEG and PNG images to WebP format.""" + + +class OptionsIPAddressACL(TypedDict, total=False): + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of IP addresses with a subnet mask. + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of IP addresses for which access is prohibited. + - **deny** - List of IP addresses for which access is allowed. + + Examples: + + - `192.168.3.2/32` + - `2a03:d000:2980:7::8/128` + """ + + policy_type: Required[Literal["allow", "deny"]] + """IP access policy type. + + Possible values: + + - **allow** - Allow access to all IPs except IPs specified in "excepted_values" + field. + - **deny** - Deny access to all IPs except IPs specified in "excepted_values" + field. + """ + + +class OptionsLimitBandwidth(TypedDict, total=False): + """Allows to control the download speed per connection.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + limit_type: Required[Literal["static", "dynamic"]] + """Method of controlling the download speed per connection. + + Possible values: + + - **static** - Use speed and buffer fields to set the download speed limit. + - **dynamic** - Use query strings **speed** and **buffer** to set the download + speed limit. + + For example, when requesting content at the link + + ``` + http://cdn.example.com/video.mp4?speed=50k&buffer=500k + ``` + + the download speed will be limited to 50kB/s after 500 kB. + """ + + buffer: int + """Amount of downloaded data after which the user will be rate limited.""" + + speed: int + """Maximum download speed per connection.""" + + +class OptionsProxyCacheKey(TypedDict, total=False): + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will not work. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Key for caching.""" + + +class OptionsProxyCacheMethodsSet(TypedDict, total=False): + """Caching for POST requests along with default GET and HEAD.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsProxyConnectTimeout(TypedDict, total=False): + """The time limit for establishing a connection with the origin.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 5s**. + """ + + +class OptionsProxyReadTimeout(TypedDict, total=False): + """ + The time limit for receiving a partial response from the origin. + If no response is received within this time, the connection will be closed. + + **Note:** + When used with a WebSocket connection, this option supports values only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[str] + """Timeout value in seconds. + + Supported range: **1s - 30s**. + """ + + +class OptionsQueryParamsBlacklist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as one object, files with other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryParamsWhitelist(TypedDict, total=False): + """ + Files with the specified query parameters are cached as different objects, files with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[SequenceNotStr[str]] + """List of query parameters.""" + + +class OptionsQueryStringForwarding(TypedDict, total=False): + """ + The Query String Forwarding feature allows for the seamless transfer of parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication tokens or tracking information, are consistently passed along from the playlist manifest to the individual media segments. + This is particularly useful for maintaining continuity in security, analytics, and any other parameter-based operations across the entire media delivery workflow. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + forward_from_file_types: Required[SequenceNotStr[str]] + """ + The `forward_from_files_types` field specifies the types of playlist files from + which parameters will be extracted and forwarded. This typically includes + formats that list multiple media chunk references, such as HLS and DASH + playlists. Parameters associated with these playlist files (like query strings + or headers) will be propagated to the chunks they reference. + """ + + forward_to_file_types: Required[SequenceNotStr[str]] + """ + The field specifies the types of media chunk files to which parameters, + extracted from playlist files, will be forwarded. These refer to the actual + segments of media content that are delivered to viewers. Ensuring the correct + parameters are forwarded to these files is crucial for maintaining the integrity + of the streaming session. + """ + + forward_except_keys: SequenceNotStr[str] + """ + The `forward_except_keys` field provides a mechanism to exclude specific + parameters from being forwarded from playlist files to media chunk files. By + listing certain keys in this field, you can ensure that these parameters are + omitted during the forwarding process. This is particularly useful for + preventing sensitive or irrelevant information from being included in requests + for media chunks, thereby enhancing security and optimizing performance. + """ + + forward_only_keys: SequenceNotStr[str] + """ + The `forward_only_keys` field allows for granular control over which specific + parameters are forwarded from playlist files to media chunk files. By specifying + certain keys, only those parameters will be propagated, ensuring that only + relevant information is passed along. This is particularly useful for security + and performance optimization, as it prevents unnecessary or sensitive data from + being included in requests for media chunks. + """ + + +class OptionsRedirectHTTPToHTTPS(TypedDict, total=False): + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsRedirectHTTPSToHTTP(TypedDict, total=False): + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled simultaneously. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsReferrerACL(TypedDict, total=False): + """Controls access to the CDN resource content for specified domain names.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """ + List of domain names or wildcard domains (without protocol: `http://` or + `https://`.) + + The meaning of the parameter depends on `policy_type` value: + + - **allow** - List of domain names for which access is prohibited. + - **deny** - List of IP domain names for which access is allowed. + + Examples: + + - `example.com` + - `*.example.com` + """ + + policy_type: Required[Literal["allow", "deny"]] + """Policy type. + + Possible values: + + - **allow** - Allow access to all domain names except the domain names specified + in `excepted_values` field. + - **deny** - Deny access to all domain names except the domain names specified + in `excepted_values` field. + """ + + +class OptionsRequestLimiter(TypedDict, total=False): + """Option allows to limit the amount of HTTP requests.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + rate: Required[int] + """Maximum request rate.""" + + rate_unit: Literal["r/s", "r/m"] + """Units of measurement for the `rate` field. + + Possible values: + + - **r/s** - Requests per second. + - **r/m** - Requests per minute. + + If the rate is less than one request per second, it is specified in request per + minute (r/m.) + """ + + +class OptionsResponseHeadersHidingPolicy(TypedDict, total=False): + """Hides HTTP headers from an origin server in the CDN response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted: Required[SequenceNotStr[str]] + """List of HTTP headers. + + Parameter meaning depends on the value of the `mode` field: + + - **show** - List of HTTP headers to hide from response. + - **hide** - List of HTTP headers to include in response. Other HTTP headers + will be hidden. + + The following headers are required and cannot be hidden from response: + + - `Connection` + - `Content-Length` + - `Content-Type` + - `Date` + - `Server` + """ + + mode: Required[Literal["hide", "show"]] + """How HTTP headers are hidden from the response. + + Possible values: + + - **show** - Hide only HTTP headers listed in the `excepted` field. + - **hide** - Hide all HTTP headers except headers listed in the "excepted" + field. + """ + + +class OptionsRewrite(TypedDict, total=False): + """Changes and redirects requests from the CDN to the origin. + + It operates according to the [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) configuration. + """ + + body: Required[str] + """Path for the Rewrite option. + + Example: + + - `/(.*) /media/$1` + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + flag: Literal["break", "last", "redirect", "permanent"] + """Flag for the Rewrite option. + + Possible values: + + - **last** - Stop processing the current set of `ngx_http_rewrite_module` + directives and start a search for a new location matching changed URI. + - **break** - Stop processing the current set of the Rewrite option. + - **redirect** - Return a temporary redirect with the 302 code; used when a + replacement string does not start with `http://`, `https://`, or `$scheme`. + - **permanent** - Return a permanent redirect with the 301 code. + """ + + +class OptionsSecureKey(TypedDict, total=False): + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + key: Required[Optional[str]] + """Key generated on your side that will be used for URL signing.""" + + type: Literal[0, 2] + """Type of URL signing. + + Possible types: + + - **Type 0** - Includes end user IP to secure token generation. + - **Type 2** - Excludes end user IP from secure token generation. + """ + + +class OptionsSlice(TypedDict, total=False): + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per part.) This reduces time to first byte. + + The option is based on the [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` options enabled. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsSni(TypedDict, total=False): + """ + The hostname that is added to SNI requests from CDN servers to the origin server via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not have a dedicated IP address. + If the origin server presents multiple certificates, SNI allows the origin server to know which certificate to use for the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + custom_hostname: Required[str] + """Custom SNI hostname. + + It is required if `sni_type` is set to custom. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + sni_type: Literal["dynamic", "custom"] + """SNI (Server Name Indication) type. + + Possible values: + + - **dynamic** - SNI hostname depends on `hostHeader` and `forward_host_header` + options. It has several possible combinations: + - If the `hostHeader` option is enabled and specified, SNI hostname matches the + Host header. + - If the `forward_host_header` option is enabled and has true value, SNI + hostname matches the Host header used in the request made to a CDN. + - If the `hostHeader` and `forward_host_header` options are disabled, SNI + hostname matches the primary CNAME. + - **custom** - custom SNI hostname is in use. + """ + + +class OptionsStale(TypedDict, total=False): + """Serves stale cached content in case of origin unavailability.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[ + List[ + Literal[ + "error", + "http_403", + "http_404", + "http_429", + "http_500", + "http_502", + "http_503", + "http_504", + "invalid_header", + "timeout", + "updating", + ] + ] + ] + """Defines list of errors for which "Always online" option is applied.""" + + +class OptionsStaticResponseHeadersValue(TypedDict, total=False): + name: Required[str] + """HTTP Header name. + + Restrictions: + + - Maximum 128 symbols. + - Latin letters (A-Z, a-z,) numbers (0-9,) dashes, and underscores only. + """ + + value: Required[SequenceNotStr[str]] + """Header value. + + Restrictions: + + - Maximum 512 symbols. + - Letters (a-z), numbers (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ + /|\";:?.,><{}[]). + - Must start with a letter, number, asterisk or {. + - Multiple values can be added. + """ + + always: bool + """ + Defines whether the header will be added to a response from CDN regardless of + response code. + + Possible values: + + - **true** - Header will be added to a response from CDN regardless of response + code. + - **false** - Header will be added only to the following response codes: 200, + 201, 204, 206, 301, 302, 303, 304, 307, 308. + """ + + +class OptionsStaticResponseHeaders(TypedDict, total=False): + """Custom HTTP Headers that a CDN server adds to a response.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Iterable[OptionsStaticResponseHeadersValue]] + + +class OptionsStaticHeaders(TypedDict, total=False): + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP Headers can be specified. May contain a header with multiple values. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[object] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 128 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsStaticRequestHeaders(TypedDict, total=False): + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[Dict[str, str]] + """A MAP for static headers in a format of `header_name: header_value`. + + Restrictions: + + - **Header name** - Maximum 255 symbols, may contain Latin letters (A-Z, a-z), + numbers (0-9), dashes, and underscores. + - **Header value** - Maximum 512 symbols, may contain letters (a-z), numbers + (0-9), spaces, and symbols (`~!@#%%^&\\**()-\\__=+ /|\";:?.,><{}[]). Must start + with a letter, number, asterisk or {. + """ + + +class OptionsUserAgentACL(TypedDict, total=False): + """Controls access to the content for specified User-Agents.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + excepted_values: Required[SequenceNotStr[str]] + """List of User-Agents that will be allowed/denied. + + The meaning of the parameter depends on `policy_type`: + + - **allow** - List of User-Agents for which access is prohibited. + - **deny** - List of User-Agents for which access is allowed. + + You can provide exact User-Agent strings or regular expressions. Regular + expressions must start with `~` (case-sensitive) or `~*` (case-insensitive). + + Use an empty string `""` to allow/deny access when the User-Agent header is + empty. + """ + + policy_type: Required[Literal["allow", "deny"]] + """User-Agents policy type. + + Possible values: + + - **allow** - Allow access for all User-Agents except specified in + `excepted_values` field. + - **deny** - Deny access for all User-Agents except specified in + `excepted_values` field. + """ + + +class OptionsWaap(TypedDict, total=False): + """Allows to enable WAAP (Web Application and API Protection).""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class OptionsWebsockets(TypedDict, total=False): + """Enables or disables WebSockets connections to an origin server.""" + + enabled: Required[bool] + """Controls the option state. + + Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + value: Required[bool] + """Possible values: + + - **true** - Option is enabled. + - **false** - Option is disabled. + """ + + +class Options(TypedDict, total=False): + """List of options that can be configured for the rule. + + In case of `null` value the option is not added to the rule. + Option inherits its value from the CDN resource settings. + """ + + allowed_http_methods: Annotated[Optional[OptionsAllowedHTTPMethods], PropertyInfo(alias="allowedHttpMethods")] + """HTTP methods allowed for content requests from the CDN.""" + + bot_protection: Optional[OptionsBotProtection] + """ + Allows to prevent online services from overloading and ensure your business + workflow running smoothly. + """ + + brotli_compression: Optional[OptionsBrotliCompression] + """Compresses content with Brotli on the CDN side. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. CDN only supports "Brotli compression" when the "origin shielding" feature is + activated. + 2. If a precache server is not active for a CDN resource, no compression occurs, + even if the option is enabled. + 3. `brotli_compression` is not supported with `fetch_compressed` or `slice` + options enabled. + 4. `fetch_compressed` option in CDN resource settings overrides + `brotli_compression` in rules. If you enabled `fetch_compressed` in CDN + resource and want to enable `brotli_compression` in a rule, you must specify + `fetch_compressed:false` in the rule. + """ + + browser_cache_settings: Optional[OptionsBrowserCacheSettings] + """Cache expiration time for users browsers in seconds. + + Cache expiration time is applied to the following response codes: 200, 201, 204, + 206, 301, 302, 303, 304, 307, 308. + + Responses with other codes will not be cached. + """ + + cache_http_headers: Optional[OptionsCacheHTTPHeaders] + """**Legacy option**. Use the `response_headers_hiding_policy` option instead. + + HTTP Headers that must be included in the response. + """ + + cors: Optional[OptionsCors] + """Enables or disables CORS (Cross-Origin Resource Sharing) header support. + + CORS header support allows the CDN to add the Access-Control-Allow-Origin header + to a response to a browser. + """ + + country_acl: Optional[OptionsCountryACL] + """Enables control access to content for specified countries.""" + + disable_cache: Optional[OptionsDisableCache] + """**Legacy option**. Use the `edge_cache_settings` option instead. + + Allows the complete disabling of content caching. + """ + + disable_proxy_force_ranges: Optional[OptionsDisableProxyForceRanges] + """Allows 206 responses regardless of the settings of an origin source.""" + + edge_cache_settings: Optional[OptionsEdgeCacheSettings] + """Cache expiration time for CDN servers. + + `value` and `default` fields cannot be used simultaneously. + """ + + fastedge: Optional[OptionsFastedge] + """ + Allows to configure FastEdge app to be called on different request/response + phases. + + Note: At least one of `on_request_headers`, `on_request_body`, + `on_response_headers`, or `on_response_body` must be specified. + """ + + fetch_compressed: Optional[OptionsFetchCompressed] + """Makes the CDN request compressed content from the origin. + + The origin server should support compression. CDN servers will not decompress + your content even if a user browser does not accept compression. + + Notes: + + 1. `fetch_compressed` is not supported with `gzipON` or `brotli_compression` or + `slice` options enabled. + 2. `fetch_compressed` overrides `gzipON` and `brotli_compression` in rule. If + you enable it in CDN resource and want to use `gzipON` and + `brotli_compression` in a rule, you have to specify + `"fetch_compressed": false` in the rule. + """ + + follow_origin_redirect: Optional[OptionsFollowOriginRedirect] + """ + Enables redirection from origin. If the origin server returns a redirect, the + option allows the CDN to pull the requested content from the origin server that + was returned in the redirect. + """ + + force_return: Optional[OptionsForceReturn] + """Applies custom HTTP response codes for CDN content. + + The following codes are reserved by our system and cannot be specified in this + option: 408, 444, 477, 494, 495, 496, 497, 499. + """ + + forward_host_header: Optional[OptionsForwardHostHeader] + """Forwards the Host header from a end-user request to an origin server. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + gzip_on: Annotated[Optional[OptionsGzipOn], PropertyInfo(alias="gzipOn")] + """Compresses content with gzip on the CDN end. + + CDN servers will request only uncompressed content from the origin. + + Notes: + + 1. Compression with gzip is not supported with `fetch_compressed` or `slice` + options enabled. + 2. `fetch_compressed` option in CDN resource settings overrides `gzipON` in + rules. If you enable `fetch_compressed` in CDN resource and want to enable + `gzipON` in rules, you need to specify `"fetch_compressed":false` for rules. + """ + + host_header: Annotated[Optional[OptionsHostHeader], PropertyInfo(alias="hostHeader")] + """ + Sets the Host header that CDN servers use when request content from an origin + server. Your server must be able to process requests with the chosen header. + + If the option is `null`, the Host Header value is equal to first CNAME. + + `hostHeader` and `forward_host_header` options cannot be enabled simultaneously. + """ + + ignore_cookie: Optional[OptionsIgnoreCookie] + """ + Defines whether the files with the Set-Cookies header are cached as one file or + as different ones. + """ + + ignore_query_string: Annotated[Optional[OptionsIgnoreQueryString], PropertyInfo(alias="ignoreQueryString")] + """ + How a file with different query strings is cached: either as one object (option + is enabled) or as different objects (option is disabled.) + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + image_stack: Optional[OptionsImageStack] + """ + Transforms JPG and PNG images (for example, resize or crop) and automatically + converts them to WebP or AVIF format. + """ + + ip_address_acl: Optional[OptionsIPAddressACL] + """Controls access to the CDN resource content for specific IP addresses. + + If you want to use IPs from our CDN servers IP list for IP ACL configuration, + you have to independently monitor their relevance. + + We recommend you use a script for automatically update IP ACL. + [Read more.](/docs/api-reference/cdn/ip-addresses-list/get-cdn-servers-ip-addresses) + """ + + limit_bandwidth: Optional[OptionsLimitBandwidth] + """Allows to control the download speed per connection.""" + + proxy_cache_key: Optional[OptionsProxyCacheKey] + """Allows you to modify your cache key. + + If omitted, the default value is `$request_uri`. + + Combine the specified variables to create a key for caching. + + - **$`request_uri`** + - **$scheme** + - **$uri** + + **Warning**: Enabling and changing this option can invalidate your current cache + and affect the cache hit ratio. Furthermore, the "Purge by pattern" option will + not work. + """ + + proxy_cache_methods_set: Optional[OptionsProxyCacheMethodsSet] + """Caching for POST requests along with default GET and HEAD.""" + + proxy_connect_timeout: Optional[OptionsProxyConnectTimeout] + """The time limit for establishing a connection with the origin.""" + + proxy_read_timeout: Optional[OptionsProxyReadTimeout] + """ + The time limit for receiving a partial response from the origin. If no response + is received within this time, the connection will be closed. + + **Note:** When used with a WebSocket connection, this option supports values + only in the range 1–20 seconds (instead of the usual 1–30 seconds). + """ + + query_params_blacklist: Optional[OptionsQueryParamsBlacklist] + """ + Files with the specified query parameters are cached as one object, files with + other parameters are cached as different objects. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_params_whitelist: Optional[OptionsQueryParamsWhitelist] + """ + Files with the specified query parameters are cached as different objects, files + with other parameters are cached as one object. + + `ignoreQueryString`, `query_params_whitelist` and `query_params_blacklist` + options cannot be enabled simultaneously. + """ + + query_string_forwarding: Optional[OptionsQueryStringForwarding] + """ + The Query String Forwarding feature allows for the seamless transfer of + parameters embedded in playlist files to the corresponding media chunk files. + This functionality ensures that specific attributes, such as authentication + tokens or tracking information, are consistently passed along from the playlist + manifest to the individual media segments. This is particularly useful for + maintaining continuity in security, analytics, and any other parameter-based + operations across the entire media delivery workflow. + """ + + redirect_http_to_https: Optional[OptionsRedirectHTTPToHTTPS] + """Enables redirect from HTTP to HTTPS. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + redirect_https_to_http: Optional[OptionsRedirectHTTPSToHTTP] + """Enables redirect from HTTPS to HTTP. + + `redirect_http_to_https` and `redirect_https_to_http` options cannot be enabled + simultaneously. + """ + + referrer_acl: Optional[OptionsReferrerACL] + """Controls access to the CDN resource content for specified domain names.""" + + request_limiter: Optional[OptionsRequestLimiter] + """Option allows to limit the amount of HTTP requests.""" + + response_headers_hiding_policy: Optional[OptionsResponseHeadersHidingPolicy] + """Hides HTTP headers from an origin server in the CDN response.""" + + rewrite: Optional[OptionsRewrite] + """Changes and redirects requests from the CDN to the origin. + + It operates according to the + [Nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) + configuration. + """ + + secure_key: Optional[OptionsSecureKey] + """Configures access with tokenized URLs. + + This makes impossible to access content without a valid (unexpired) token. + """ + + slice: Optional[OptionsSlice] + """ + Requests and caches files larger than 10 MB in parts (no larger than 10 MB per + part.) This reduces time to first byte. + + The option is based on the + [Slice](https://nginx.org/en/docs/http/ngx_http_slice_module.html) module. + + Notes: + + 1. Origin must support HTTP Range requests. + 2. Not supported with `gzipON`, `brotli_compression` or `fetch_compressed` + options enabled. + """ + + sni: Optional[OptionsSni] + """ + The hostname that is added to SNI requests from CDN servers to the origin server + via HTTPS. + + SNI is generally only required if your origin uses shared hosting or does not + have a dedicated IP address. If the origin server presents multiple + certificates, SNI allows the origin server to know which certificate to use for + the connection. + + The option works only if `originProtocol` parameter is `HTTPS` or `MATCH`. + """ + + stale: Optional[OptionsStale] + """Serves stale cached content in case of origin unavailability.""" + + static_response_headers: Optional[OptionsStaticResponseHeaders] + """Custom HTTP Headers that a CDN server adds to a response.""" + + static_headers: Annotated[Optional[OptionsStaticHeaders], PropertyInfo(alias="staticHeaders")] + """**Legacy option**. Use the `static_response_headers` option instead. + + Custom HTTP Headers that a CDN server adds to response. Up to fifty custom HTTP + Headers can be specified. May contain a header with multiple values. + """ + + static_request_headers: Annotated[Optional[OptionsStaticRequestHeaders], PropertyInfo(alias="staticRequestHeaders")] + """Custom HTTP Headers for a CDN server to add to request. + + Up to fifty custom HTTP Headers can be specified. + """ + + user_agent_acl: Optional[OptionsUserAgentACL] + """Controls access to the content for specified User-Agents.""" + + waap: Optional[OptionsWaap] + """Allows to enable WAAP (Web Application and API Protection).""" + + websockets: Optional[OptionsWebsockets] + """Enables or disables WebSockets connections to an origin server.""" diff --git a/src/gcore/types/cdn/shield_aggregated_stats.py b/src/gcore/types/cdn/shield_aggregated_stats.py new file mode 100644 index 00000000..e13cf582 --- /dev/null +++ b/src/gcore/types/cdn/shield_aggregated_stats.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["ShieldAggregatedStats"] + + +class ShieldAggregatedStats(BaseModel): + api_1_example: Optional[object] = FieldInfo(alias="1 (example)", default=None) + """CDN resource ID for which statistics data is shown.""" + + metrics: Optional[object] = None + """Statistics parameters.""" + + resource: Optional[object] = None + """Resources IDs by which statistics data is grouped.""" + + shield_usage: Optional[str] = None + """Number of CDN resources that used origin shielding.""" diff --git a/src/gcore/types/cdn/shield_list_response.py b/src/gcore/types/cdn/shield_list_response.py new file mode 100644 index 00000000..4449e462 --- /dev/null +++ b/src/gcore/types/cdn/shield_list_response.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["ShieldListResponse", "ShieldListResponseItem"] + + +class ShieldListResponseItem(BaseModel): + id: Optional[int] = None + """Origin shielding location ID.""" + + city: Optional[str] = None + """City of origin shielding location.""" + + country: Optional[str] = None + """Country of origin shielding location.""" + + datacenter: Optional[str] = None + """Name of origin shielding location datacenter.""" + + +ShieldListResponse: TypeAlias = List[ShieldListResponseItem] diff --git a/src/gcore/types/cdn/ssl_detail.py b/src/gcore/types/cdn/ssl_detail.py new file mode 100644 index 00000000..aa57c7d5 --- /dev/null +++ b/src/gcore/types/cdn/ssl_detail.py @@ -0,0 +1,62 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["SslDetail"] + + +class SslDetail(BaseModel): + id: Optional[int] = None + """SSL certificate ID.""" + + automated: Optional[bool] = None + """How the SSL certificate was issued. + + Possible values: + + - **true** - Certificate was issued automatically. + - **false** - Certificate was added by a use. + """ + + cert_issuer: Optional[str] = None + """Name of the certification center issued the SSL certificate.""" + + cert_subject_alt: Optional[str] = None + """Alternative domain names that the SSL certificate secures.""" + + cert_subject_cn: Optional[str] = None + """Domain name that the SSL certificate secures.""" + + deleted: Optional[bool] = None + """Defines whether the certificate has been deleted. Parameter is **deprecated**. + + Possible values: + + - **true** - Certificate has been deleted. + - **false** - Certificate has not been deleted. + """ + + has_related_resources: Optional[bool] = FieldInfo(alias="hasRelatedResources", default=None) + """Defines whether the SSL certificate is used by a CDN resource. + + Possible values: + + - **true** - Certificate is used by a CDN resource. + - **false** - Certificate is not used by a CDN resource. + """ + + name: Optional[str] = None + """SSL certificate name.""" + + ssl_certificate_chain: Optional[str] = FieldInfo(alias="sslCertificateChain", default=None) + """Parameter is **deprecated**.""" + + validity_not_after: Optional[str] = None + """Date when certificate become untrusted (ISO 8601/RFC 3339 format, UTC.)""" + + validity_not_before: Optional[str] = None + """Date when certificate become valid (ISO 8601/RFC 3339 format, UTC.)""" diff --git a/src/gcore/types/cdn/ssl_detail_list.py b/src/gcore/types/cdn/ssl_detail_list.py new file mode 100644 index 00000000..8a6a991b --- /dev/null +++ b/src/gcore/types/cdn/ssl_detail_list.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .ssl_detail import SslDetail + +__all__ = ["SslDetailList"] + +SslDetailList: TypeAlias = List[SslDetail] diff --git a/src/gcore/types/cdn/ssl_request_status.py b/src/gcore/types/cdn/ssl_request_status.py new file mode 100644 index 00000000..e0577790 --- /dev/null +++ b/src/gcore/types/cdn/ssl_request_status.py @@ -0,0 +1,137 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["SslRequestStatus", "LatestStatus", "Status"] + + +class LatestStatus(BaseModel): + """Detailed information about last attempt to issue a Let's Encrypt certificate.""" + + id: Optional[int] = None + """ID of the attempt to issue the Let's Encrypt certificate.""" + + created: Optional[str] = None + """ + Date and time when the issuing attempt status was created (ISO 8601/RFC 3339 + format, UTC). + """ + + details: Optional[str] = None + """ + Detailed description of the error that occurred when trying to issue a Let's + Encrypt certificate. + """ + + error: Optional[str] = None + """ + Brief description of the error that occurred when trying to issue a Let's + Encrypt certificate. + """ + + retry_after: Optional[str] = None + """ + Date indicating when the certificate issuance limit will be lifted (ISO 8601/RFC + 3339 format, UTC). + + It is filled in only if error = RateLimited. + """ + + status: Optional[str] = None + """Status of the attempt to issue the Let's Encrypt certificate. + + Possible values: + + - **Done** - Attempt is successful. Let's Encrypt certificate was issued. + - **Failed** - Attempt failed. Let's Encrypt certificate was not issued. + - **Cancelled** - Attempt is canceled. Let's Encrypt certificate was not issued. + """ + + +class Status(BaseModel): + id: Optional[int] = None + """ID of the attempt to issue the Let's Encrypt certificate.""" + + created: Optional[str] = None + """ + Date and time when the issuing attempt status was created (ISO 8601/RFC 3339 + format, UTC). + """ + + details: Optional[str] = None + """ + Detailed description of the error that occurred when trying to issue a Let's + Encrypt certificate. + """ + + error: Optional[str] = None + """ + Brief description of the error that occurred when trying to issue a Let's + Encrypt certificate. + """ + + retry_after: Optional[str] = None + """ + Date indicating when the certificate issuance limit will be lifted (ISO 8601/RFC + 3339 format, UTC). + + It is filled in only if error = RateLimited. + """ + + status: Optional[str] = None + """Status of the attempt to issue the Let's Encrypt certificate. + + Possible values: + + - **Done** - Attempt is successful. Let's Encrypt certificate was issued. + - **Failed** - Attempt failed. Let's Encrypt certificate was not issued. + - **Cancelled** - Attempt is canceled. Let's Encrypt certificate was not issued. + """ + + +class SslRequestStatus(BaseModel): + id: Optional[int] = None + """ID of the attempt to issue a Let's Encrypt certificate.""" + + active: Optional[bool] = None + """Defines whether the Let's Encrypt certificate issuing process is active. + + Possible values: + + - **true** - Issuing process is active. + - **false** - Issuing process is completed. + """ + + attempts_count: Optional[int] = None + """Number of attempts to issue the Let's Encrypt certificate.""" + + finished: Optional[str] = None + """ + Date when the process of issuing a Let's Encrypt certificate was finished (ISO + 8601/RFC 3339 format, UTC). + + The field is **null** if the issuing process is not finished. + """ + + latest_status: Optional[LatestStatus] = None + """Detailed information about last attempt to issue a Let's Encrypt certificate.""" + + next_attempt_time: Optional[str] = None + """ + Time of the next scheduled attempt to issue the Let's Encrypt certificate (ISO + 8601/RFC 3339 format, UTC). + """ + + resource: Optional[int] = None + """CDN resource ID.""" + + started: Optional[str] = None + """ + Date when the process of issuing a Let's Encrypt certificate was started (ISO + 8601/RFC 3339 format, UTC). + """ + + statuses: Optional[List[Status]] = None + """Detailed information about attempts to issue a Let's Encrypt certificate.""" diff --git a/src/gcore/types/cdn/statistic_get_logs_usage_aggregated_params.py b/src/gcore/types/cdn/statistic_get_logs_usage_aggregated_params.py new file mode 100644 index 00000000..e5dff95c --- /dev/null +++ b/src/gcore/types/cdn/statistic_get_logs_usage_aggregated_params.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetLogsUsageAggregatedParams"] + + +class StatisticGetLogsUsageAggregatedParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.)""" + + to: Required[str] + """End of the requested time period (ISO 8601/RFC 3339 format, UTC.)""" + + flat: bool + """The way the parameters are arranged in the response. + + Possible values: + + - **true** – Flat structure is used. + - **false** – Embedded structure is used (default.) + """ + + group_by: str + """Output data grouping. + + Possible value: + + - **resource** - Data is grouped by CDN resources. + """ + + resource: int + """CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + """ diff --git a/src/gcore/types/cdn/statistic_get_logs_usage_series_params.py b/src/gcore/types/cdn/statistic_get_logs_usage_series_params.py new file mode 100644 index 00000000..400835af --- /dev/null +++ b/src/gcore/types/cdn/statistic_get_logs_usage_series_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetLogsUsageSeriesParams"] + + +class StatisticGetLogsUsageSeriesParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.)""" + + to: Required[str] + """End of the requested time period (ISO 8601/RFC 3339 format, UTC.)""" + + resource: int + """CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + """ diff --git a/src/gcore/types/cdn/statistic_get_resource_usage_aggregated_params.py b/src/gcore/types/cdn/statistic_get_resource_usage_aggregated_params.py new file mode 100644 index 00000000..ccf15dac --- /dev/null +++ b/src/gcore/types/cdn/statistic_get_resource_usage_aggregated_params.py @@ -0,0 +1,140 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetResourceUsageAggregatedParams"] + + +class StatisticGetResourceUsageAggregatedParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.)""" + + metrics: Required[str] + """Types of statistics data. + + Possible values: + + - **`upstream_bytes`** – Traffic in bytes from an origin server to CDN servers + or to origin shielding when used. + - **`sent_bytes`** – Traffic in bytes from CDN servers to clients. + - **`shield_bytes`** – Traffic in bytes from origin shielding to CDN servers. + - **`backblaze_bytes`** - Traffic in bytes from Backblaze origin. + - **`total_bytes`** – `shield_bytes`, `upstream_bytes` and `sent_bytes` + combined. + - **`cdn_bytes`** – `sent_bytes` and `shield_bytes` combined. + - **requests** – Number of requests to edge servers. + - **`responses_2xx`** – Number of 2xx response codes. + - **`responses_3xx`** – Number of 3xx response codes. + - **`responses_4xx`** – Number of 4xx response codes. + - **`responses_5xx`** – Number of 5xx response codes. + - **`responses_hit`** – Number of responses with the header Cache: HIT. + - **`responses_miss`** – Number of responses with the header Cache: MISS. + - **`response_types`** – Statistics by content type. It returns a number of + responses for content with different MIME types. + - **`cache_hit_traffic_ratio`** – Formula: 1 - `upstream_bytes` / `sent_bytes`. + We deduct the non-cached traffic from the total traffic amount. + - **`cache_hit_requests_ratio`** – Formula: `responses_hit` / requests. The + share of sending cached content. + - **`shield_traffic_ratio`** – Formula: (`shield_bytes` - `upstream_bytes`) / + `shield_bytes`. The efficiency of the Origin Shielding: how much more traffic + is sent from the Origin Shielding than from the origin. + - **`image_processed`** - Number of images transformed on the Image optimization + service. + - **`request_time`** - Time elapsed between the first bytes of a request were + processed and logging after the last bytes were sent to a user. + - **`upstream_response_time`** - Number of milliseconds it took to receive a + response from an origin. If upstream `response_time_` contains several + indications for one request (in case of more than 1 origin), we summarize + them. In case of aggregating several queries, the average of this amount is + calculated. + - **`95_percentile`** - Represents the 95th percentile of network bandwidth + usage in bytes per second. This means that 95% of the time, the network + resource usage was below this value. + - **`max_bandwidth`** - The maximum network bandwidth that was used during the + selected time represented in bytes per second. + - **`min_bandwidth`** - The minimum network bandwidth that was used during the + selected time represented in bytes per second. + + Metrics **`upstream_response_time`** and **`request_time`** should be requested + separately from other metrics + """ + + service: Required[str] + """Service name. + + Possible value: + + - CDN + """ + + to: Required[str] + """End of the requested time period (ISO 8601/RFC 3339 format, UTC.)""" + + countries: str + """ + Names of countries for which data should be displayed. English short name from + [ISO 3166 standard][1] without the definite article ("the") should be used. + + [1]: https://www.iso.org/obp/ui/#search/code/ + + To request multiple values, use: + + - &countries=france&countries=denmark + """ + + flat: bool + """The way the parameters are arranged in the response. + + Possible values: + + - **true** – Flat structure is used. + - **false** – Embedded structure is used (default.) + """ + + group_by: str + """Output data grouping. + + Possible values: + + - **resource** – Data is grouped by CDN resources IDs. + - **region** – Data is grouped by regions of CDN edge servers. + - **country** – Data is grouped by countries of CDN edge servers. + - **vhost** – Data is grouped by resources CNAMEs. + - **`client_country`** - Data is grouped by countries, based on end-users' + location. + + To request multiple values, use: + + - &`group_by`=region&`group_by`=resource + """ + + regions: str + """Regions for which data is displayed. + + Possible values: + + - **na** – North America + - **eu** – Europe + - **cis** – Commonwealth of Independent States + - **asia** – Asia + - **au** – Australia + - **latam** – Latin America + - **me** – Middle East + - **africa** - Africa + - **sa** - South America + """ + + resource: int + """CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + """ diff --git a/src/gcore/types/cdn/statistic_get_resource_usage_series_params.py b/src/gcore/types/cdn/statistic_get_resource_usage_series_params.py new file mode 100644 index 00000000..27b963f5 --- /dev/null +++ b/src/gcore/types/cdn/statistic_get_resource_usage_series_params.py @@ -0,0 +1,136 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetResourceUsageSeriesParams"] + + +class StatisticGetResourceUsageSeriesParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.)""" + + granularity: Required[str] + """Duration of the time blocks into which the data will be divided. + + Possible values: + + - **1m** - available only for up to 1 month in the past. + - **5m** + - **15m** + - **1h** + - **1d** + """ + + metrics: Required[str] + """Types of statistics data. + + Possible values: + + - **`upstream_bytes`** – Traffic in bytes from an origin server to CDN servers + or to origin shielding when used. + - **`sent_bytes`** – Traffic in bytes from CDN servers to clients. + - **`shield_bytes`** – Traffic in bytes from origin shielding to CDN servers. + - **`backblaze_bytes`** - Traffic in bytes from Backblaze origin. + - **`total_bytes`** – `shield_bytes`, `upstream_bytes` and `sent_bytes` + combined. + - **`cdn_bytes`** – `sent_bytes` and `shield_bytes` combined. + - **requests** – Number of requests to edge servers. + - **`responses_2xx`** – Number of 2xx response codes. + - **`responses_3xx`** – Number of 3xx response codes. + - **`responses_4xx`** – Number of 4xx response codes. + - **`responses_5xx`** – Number of 5xx response codes. + - **`responses_hit`** – Number of responses with the header Cache: HIT. + - **`responses_miss`** – Number of responses with the header Cache: MISS. + - **`response_types`** – Statistics by content type. It returns a number of + responses for content with different MIME types. + - **`cache_hit_traffic_ratio`** – Formula: 1 - `upstream_bytes` / `sent_bytes`. + We deduct the non-cached traffic from the total traffic amount. + - **`cache_hit_requests_ratio`** – Formula: `responses_hit` / requests. The + share of sending cached content. + - **`shield_traffic_ratio`** – Formula: (`shield_bytes` - `upstream_bytes`) / + `shield_bytes`. The efficiency of the Origin Shielding: how much more traffic + is sent from the Origin Shielding than from the origin. + - **`image_processed`** - Number of images transformed on the Image optimization + service. + - **`request_time`** - Time elapsed between the first bytes of a request were + processed and logging after the last bytes were sent to a user. + - **`upstream_response_time`** - Number of milliseconds it took to receive a + response from an origin. If upstream `response_time_` contains several + indications for one request (in case of more than 1 origin), we summarize + them. In case of aggregating several queries, the average of this amount is + calculated. + + Metrics **`upstream_response_time`** and **`request_time`** should be requested + separately from other metrics + """ + + service: Required[str] + """Service name. + + Possible value: + + - CDN + """ + + to: Required[str] + """End of the requested time period (ISO 8601/RFC 3339 format, UTC.)""" + + countries: str + """ + Names of countries for which data should be displayed. English short name from + [ISO 3166 standard][1] without the definite article ("the") should be used. + + [1]: https://www.iso.org/obp/ui/#search/code/ + + To request multiple values, use: + + - &countries=france&countries=denmark + """ + + group_by: str + """Output data grouping. + + Possible values: + + - **resource** – Data is grouped by CDN resources IDs. + - **region** – Data is grouped by regions of CDN edge servers. + - **country** – Data is grouped by countries of CDN edge servers. + - **vhost** – Data is grouped by resources CNAMEs. + - **`client_country`** - Data is grouped by countries, based on end-users' + location. + + To request multiple values, use: + + - &`group_by`=region&`group_by`=resource + """ + + regions: str + """Regions for which data is displayed. + + Possible values: + + - **na** – North America + - **eu** – Europe + - **cis** – Commonwealth of Independent States + - **asia** – Asia + - **au** – Australia + - **latam** – Latin America + - **me** – Middle East + - **africa** - Africa + - **sa** - South America + """ + + resource: int + """CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + """ diff --git a/src/gcore/types/cdn/statistic_get_shield_usage_aggregated_params.py b/src/gcore/types/cdn/statistic_get_shield_usage_aggregated_params.py new file mode 100644 index 00000000..f40579b7 --- /dev/null +++ b/src/gcore/types/cdn/statistic_get_shield_usage_aggregated_params.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetShieldUsageAggregatedParams"] + + +class StatisticGetShieldUsageAggregatedParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.)""" + + to: Required[str] + """End of the requested time period (ISO 8601/RFC 3339 format, UTC.)""" + + flat: bool + """The way the parameters are arranged in the response. + + Possible values: + + - **true** – Flat structure is used. + - **false** – Embedded structure is used (default.) + """ + + group_by: str + """Output data grouping. + + Possible value: + + - **resource** - Data is grouped by CDN resources. + """ + + resource: int + """CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + """ diff --git a/src/gcore/types/cdn/statistic_get_shield_usage_series_params.py b/src/gcore/types/cdn/statistic_get_shield_usage_series_params.py new file mode 100644 index 00000000..3ba5ad5a --- /dev/null +++ b/src/gcore/types/cdn/statistic_get_shield_usage_series_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetShieldUsageSeriesParams"] + + +class StatisticGetShieldUsageSeriesParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Beginning of the requested time period (ISO 8601/RFC 3339 format, UTC.)""" + + to: Required[str] + """End of the requested time period (ISO 8601/RFC 3339 format, UTC.)""" + + resource: int + """CDN resources IDs by that statistics data is grouped. + + To request multiple values, use: + + - &resource=1&resource=2 + + If CDN resource ID is not specified, data related to all CDN resources is + returned. + """ diff --git a/src/gcore/types/cdn/trusted_ca_certificate_create_params.py b/src/gcore/types/cdn/trusted_ca_certificate_create_params.py new file mode 100644 index 00000000..0240b6df --- /dev/null +++ b/src/gcore/types/cdn/trusted_ca_certificate_create_params.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["TrustedCaCertificateCreateParams"] + + +class TrustedCaCertificateCreateParams(TypedDict, total=False): + name: Required[str] + """CA certificate name. + + It must be unique. + """ + + ssl_certificate: Required[Annotated[str, PropertyInfo(alias="sslCertificate")]] + """Public part of the CA certificate. + + It must be in the PEM format. + """ diff --git a/src/gcore/types/cdn/trusted_ca_certificate_list_params.py b/src/gcore/types/cdn/trusted_ca_certificate_list_params.py new file mode 100644 index 00000000..468e9a37 --- /dev/null +++ b/src/gcore/types/cdn/trusted_ca_certificate_list_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["TrustedCaCertificateListParams"] + + +class TrustedCaCertificateListParams(TypedDict, total=False): + automated: bool + """How the certificate was issued. + + Possible values: + + - **true** – Certificate was issued automatically. + - **false** – Certificate was added by a user. + """ + + resource_id: int + """CDN resource ID for which the certificates are requested.""" + + validity_not_after_lte: str + """ + Date and time when the certificate become untrusted (ISO 8601/RFC 3339 format, + UTC.) + + Response will contain certificates valid until the specified time. + """ diff --git a/src/gcore/types/cdn/trusted_ca_certificate_replace_params.py b/src/gcore/types/cdn/trusted_ca_certificate_replace_params.py new file mode 100644 index 00000000..882017d1 --- /dev/null +++ b/src/gcore/types/cdn/trusted_ca_certificate_replace_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["TrustedCaCertificateReplaceParams"] + + +class TrustedCaCertificateReplaceParams(TypedDict, total=False): + name: Required[str] + """CA certificate name. + + It must be unique. + """ diff --git a/src/gcore/types/cdn/usage_series_stats.py b/src/gcore/types/cdn/usage_series_stats.py new file mode 100644 index 00000000..f6ab393d --- /dev/null +++ b/src/gcore/types/cdn/usage_series_stats.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["UsageSeriesStats", "UsageSeriesStatItem"] + + +class UsageSeriesStatItem(BaseModel): + active_from: Optional[str] = None + """Date and time when paid feature was enabled (ISO 8601/RFC 3339 format, UTC.)""" + + active_to: Optional[str] = None + """Date and time when paid feature was disabled (ISO 8601/RFC 3339 format, UTC.) + + It returns **null** if the paid feature is enabled. + """ + + client_id: Optional[int] = None + """Client ID.""" + + cname: Optional[str] = None + """CDN resource CNAME.""" + + resource_id: Optional[int] = None + """CDN resource ID.""" + + +UsageSeriesStats: TypeAlias = List[UsageSeriesStatItem] diff --git a/src/gcore/types/cloud/__init__.py b/src/gcore/types/cloud/__init__.py new file mode 100644 index 00000000..450b32e1 --- /dev/null +++ b/src/gcore/types/cloud/__init__.py @@ -0,0 +1,183 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .tag import Tag as Tag +from .task import Task as Task +from .image import Image as Image +from .route import Route as Route +from .member import Member as Member +from .region import Region as Region +from .secret import Secret as Secret +from .subnet import Subnet as Subnet +from .volume import Volume as Volume +from .console import Console as Console +from .logging import Logging as Logging +from .network import Network as Network +from .project import Project as Project +from .ssh_key import SSHKey as SSHKey +from .instance import Instance as Instance +from .registry import Registry as Registry +from .snapshot import Snapshot as Snapshot +from .gpu_image import GPUImage as GPUImage +from .ip_ranges import IPRanges as IPRanges +from .file_share import FileShare as FileShare +from .image_list import ImageList as ImageList +from .ip_version import IPVersion as IPVersion +from .floating_ip import FloatingIP as FloatingIP +from .http_method import HTTPMethod as HTTPMethod +from .pool_status import PoolStatus as PoolStatus +from .ddos_profile import DDOSProfile as DDOSProfile +from .lb_algorithm import LbAlgorithm as LbAlgorithm +from .registry_tag import RegistryTag as RegistryTag +from .task_id_list import TaskIDList as TaskIDList +from .usage_report import UsageReport as UsageReport +from .fixed_address import FixedAddress as FixedAddress +from .instance_list import InstanceList as InstanceList +from .ip_assignment import IPAssignment as IPAssignment +from .load_balancer import LoadBalancer as LoadBalancer +from .member_status import MemberStatus as MemberStatus +from .registry_list import RegistryList as RegistryList +from .blackhole_port import BlackholePort as BlackholePort +from .gpu_image_list import GPUImageList as GPUImageList +from .health_monitor import HealthMonitor as HealthMonitor +from .security_group import SecurityGroup as SecurityGroup +from .audit_log_entry import AuditLogEntry as AuditLogEntry +from .listener_status import ListenerStatus as ListenerStatus +from .network_details import NetworkDetails as NetworkDetails +from .placement_group import PlacementGroup as PlacementGroup +from .ssh_key_created import SSHKeyCreated as SSHKeyCreated +from .baremetal_flavor import BaremetalFlavor as BaremetalFlavor +from .floating_address import FloatingAddress as FloatingAddress +from .lb_pool_protocol import LbPoolProtocol as LbPoolProtocol +from .task_list_params import TaskListParams as TaskListParams +from .network_interface import NetworkInterface as NetworkInterface +from .region_get_params import RegionGetParams as RegionGetParams +from .reserved_fixed_ip import ReservedFixedIP as ReservedFixedIP +from .ddos_profile_field import DDOSProfileField as DDOSProfileField +from .floating_ip_status import FloatingIPStatus as FloatingIPStatus +from .instance_interface import InstanceInterface as InstanceInterface +from .instance_isolation import InstanceIsolation as InstanceIsolation +from .load_balancer_pool import LoadBalancerPool as LoadBalancerPool +from .region_list_params import RegionListParams as RegionListParams +from .secret_list_params import SecretListParams as SecretListParams +from .volume_list_params import VolumeListParams as VolumeListParams +from .billing_reservation import BillingReservation as BillingReservation +from .ddos_profile_status import DDOSProfileStatus as DDOSProfileStatus +from .fixed_address_short import FixedAddressShort as FixedAddressShort +from .interface_ip_family import InterfaceIPFamily as InterfaceIPFamily +from .k8s_cluster_version import K8SClusterVersion as K8SClusterVersion +from .network_list_params import NetworkListParams as NetworkListParams +from .project_list_params import ProjectListParams as ProjectListParams +from .provisioning_status import ProvisioningStatus as ProvisioningStatus +from .security_group_rule import SecurityGroupRule as SecurityGroupRule +from .session_persistence import SessionPersistence as SessionPersistence +from .ssh_key_list_params import SSHKeyListParams as SSHKeyListParams +from .billing_reservations import BillingReservations as BillingReservations +from .cost_report_detailed import CostReportDetailed as CostReportDetailed +from .floating_ip_detailed import FloatingIPDetailed as FloatingIPDetailed +from .instance_list_params import InstanceListParams as InstanceListParams +from .lb_listener_protocol import LbListenerProtocol as LbListenerProtocol +from .load_balancer_status import LoadBalancerStatus as LoadBalancerStatus +from .placement_group_list import PlacementGroupList as PlacementGroupList +from .tag_update_map_param import TagUpdateMapParam as TagUpdateMapParam +from .volume_create_params import VolumeCreateParams as VolumeCreateParams +from .volume_delete_params import VolumeDeleteParams as VolumeDeleteParams +from .volume_resize_params import VolumeResizeParams as VolumeResizeParams +from .volume_update_params import VolumeUpdateParams as VolumeUpdateParams +from .allowed_address_pairs import AllowedAddressPairs as AllowedAddressPairs +from .audit_log_list_params import AuditLogListParams as AuditLogListParams +from .baremetal_flavor_list import BaremetalFlavorList as BaremetalFlavorList +from .ddos_profile_template import DDOSProfileTemplate as DDOSProfileTemplate +from .health_monitor_status import HealthMonitorStatus as HealthMonitorStatus +from .load_balancer_l7_rule import LoadBalancerL7Rule as LoadBalancerL7Rule +from .load_balancer_metrics import LoadBalancerMetrics as LoadBalancerMetrics +from .network_create_params import NetworkCreateParams as NetworkCreateParams +from .network_update_params import NetworkUpdateParams as NetworkUpdateParams +from .project_create_params import ProjectCreateParams as ProjectCreateParams +from .project_update_params import ProjectUpdateParams as ProjectUpdateParams +from .ssh_key_create_params import SSHKeyCreateParams as SSHKeyCreateParams +from .ssh_key_update_params import SSHKeyUpdateParams as SSHKeyUpdateParams +from .cost_report_aggregated import CostReportAggregated as CostReportAggregated +from .file_share_list_params import FileShareListParams as FileShareListParams +from .instance_action_params import InstanceActionParams as InstanceActionParams +from .instance_create_params import InstanceCreateParams as InstanceCreateParams +from .instance_delete_params import InstanceDeleteParams as InstanceDeleteParams +from .instance_resize_params import InstanceResizeParams as InstanceResizeParams +from .instance_update_params import InstanceUpdateParams as InstanceUpdateParams +from .lb_health_monitor_type import LbHealthMonitorType as LbHealthMonitorType +from .network_interface_list import NetworkInterfaceList as NetworkInterfaceList +from .quota_get_all_response import QuotaGetAllResponse as QuotaGetAllResponse +from .registry_create_params import RegistryCreateParams as RegistryCreateParams +from .registry_resize_params import RegistryResizeParams as RegistryResizeParams +from .floating_ip_list_params import FloatingIPListParams as FloatingIPListParams +from .load_balancer_l7_policy import LoadBalancerL7Policy as LoadBalancerL7Policy +from .load_balancer_pool_list import LoadBalancerPoolList as LoadBalancerPoolList +from .usage_report_get_params import UsageReportGetParams as UsageReportGetParams +from .ddos_profile_option_list import DDOSProfileOptionList as DDOSProfileOptionList +from .file_share_create_params import FileShareCreateParams as FileShareCreateParams +from .file_share_resize_params import FileShareResizeParams as FileShareResizeParams +from .file_share_update_params import FileShareUpdateParams as FileShareUpdateParams +from .k8s_cluster_version_list import K8SClusterVersionList as K8SClusterVersionList +from .load_balancer_get_params import LoadBalancerGetParams as LoadBalancerGetParams +from .load_balancer_statistics import LoadBalancerStatistics as LoadBalancerStatistics +from .floating_ip_assign_params import FloatingIPAssignParams as FloatingIPAssignParams +from .floating_ip_create_params import FloatingIPCreateParams as FloatingIPCreateParams +from .floating_ip_update_params import FloatingIPUpdateParams as FloatingIPUpdateParams +from .inference_region_capacity import InferenceRegionCapacity as InferenceRegionCapacity +from .load_balancer_flavor_list import LoadBalancerFlavorList as LoadBalancerFlavorList +from .load_balancer_list_params import LoadBalancerListParams as LoadBalancerListParams +from .load_balancer_status_list import LoadBalancerStatusList as LoadBalancerStatusList +from .quota_get_global_response import QuotaGetGlobalResponse as QuotaGetGlobalResponse +from .volume_change_type_params import VolumeChangeTypeParams as VolumeChangeTypeParams +from .instance_metrics_time_unit import InstanceMetricsTimeUnit as InstanceMetricsTimeUnit +from .load_balancer_l7_rule_list import LoadBalancerL7RuleList as LoadBalancerL7RuleList +from .load_balancer_metrics_list import LoadBalancerMetricsList as LoadBalancerMetricsList +from .security_group_copy_params import SecurityGroupCopyParams as SecurityGroupCopyParams +from .security_group_list_params import SecurityGroupListParams as SecurityGroupListParams +from .ddos_profile_template_field import DDOSProfileTemplateField as DDOSProfileTemplateField +from .instance_get_console_params import InstanceGetConsoleParams as InstanceGetConsoleParams +from .laas_index_retention_policy import LaasIndexRetentionPolicy as LaasIndexRetentionPolicy +from .lb_session_persistence_type import LbSessionPersistenceType as LbSessionPersistenceType +from .load_balancer_create_params import LoadBalancerCreateParams as LoadBalancerCreateParams +from .load_balancer_flavor_detail import LoadBalancerFlavorDetail as LoadBalancerFlavorDetail +from .load_balancer_instance_role import LoadBalancerInstanceRole as LoadBalancerInstanceRole +from .load_balancer_listener_list import LoadBalancerListenerList as LoadBalancerListenerList +from .load_balancer_resize_params import LoadBalancerResizeParams as LoadBalancerResizeParams +from .load_balancer_update_params import LoadBalancerUpdateParams as LoadBalancerUpdateParams +from .task_acknowledge_all_params import TaskAcknowledgeAllParams as TaskAcknowledgeAllParams +from .load_balancer_l7_policy_list import LoadBalancerL7PolicyList as LoadBalancerL7PolicyList +from .quota_get_by_region_response import QuotaGetByRegionResponse as QuotaGetByRegionResponse +from .security_group_create_params import SecurityGroupCreateParams as SecurityGroupCreateParams +from .security_group_update_params import SecurityGroupUpdateParams as SecurityGroupUpdateParams +from .load_balancer_failover_params import LoadBalancerFailoverParams as LoadBalancerFailoverParams +from .load_balancer_listener_detail import LoadBalancerListenerDetail as LoadBalancerListenerDetail +from .placement_group_create_params import PlacementGroupCreateParams as PlacementGroupCreateParams +from .reserved_fixed_ip_list_params import ReservedFixedIPListParams as ReservedFixedIPListParams +from .volume_snapshot_create_params import VolumeSnapshotCreateParams as VolumeSnapshotCreateParams +from .volume_snapshot_update_params import VolumeSnapshotUpdateParams as VolumeSnapshotUpdateParams +from .cost_report_aggregated_monthly import CostReportAggregatedMonthly as CostReportAggregatedMonthly +from .inference_region_capacity_list import InferenceRegionCapacityList as InferenceRegionCapacityList +from .load_balancer_operating_status import LoadBalancerOperatingStatus as LoadBalancerOperatingStatus +from .billing_reservation_list_params import BillingReservationListParams as BillingReservationListParams +from .cost_report_get_detailed_params import CostReportGetDetailedParams as CostReportGetDetailedParams +from .reserved_fixed_ip_create_params import ReservedFixedIPCreateParams as ReservedFixedIPCreateParams +from .reserved_fixed_ip_update_params import ReservedFixedIPUpdateParams as ReservedFixedIPUpdateParams +from .volume_attach_to_instance_params import VolumeAttachToInstanceParams as VolumeAttachToInstanceParams +from .cost_report_get_aggregated_params import CostReportGetAggregatedParams as CostReportGetAggregatedParams +from .laas_index_retention_policy_param import LaasIndexRetentionPolicyParam as LaasIndexRetentionPolicyParam +from .load_balancer_member_connectivity import LoadBalancerMemberConnectivity as LoadBalancerMemberConnectivity +from .volume_detach_from_instance_params import VolumeDetachFromInstanceParams as VolumeDetachFromInstanceParams +from .secret_upload_tls_certificate_params import SecretUploadTlsCertificateParams as SecretUploadTlsCertificateParams +from .instance_assign_security_group_params import ( + InstanceAssignSecurityGroupParams as InstanceAssignSecurityGroupParams, +) +from .instance_add_to_placement_group_params import ( + InstanceAddToPlacementGroupParams as InstanceAddToPlacementGroupParams, +) +from .instance_unassign_security_group_params import ( + InstanceUnassignSecurityGroupParams as InstanceUnassignSecurityGroupParams, +) +from .cost_report_get_aggregated_monthly_params import ( + CostReportGetAggregatedMonthlyParams as CostReportGetAggregatedMonthlyParams, +) diff --git a/src/gcore/types/cloud/allowed_address_pairs.py b/src/gcore/types/cloud/allowed_address_pairs.py new file mode 100644 index 00000000..8f3ffcab --- /dev/null +++ b/src/gcore/types/cloud/allowed_address_pairs.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["AllowedAddressPairs"] + + +class AllowedAddressPairs(BaseModel): + ip_address: str + """Subnet mask or IP address of the port specified in `allowed_address_pairs`""" + + mac_address: Optional[str] = None + """MAC address of the port specified in `allowed_address_pairs`""" diff --git a/src/gcore/types/cloud/audit_log_entry.py b/src/gcore/types/cloud/audit_log_entry.py new file mode 100644 index 00000000..80a077ae --- /dev/null +++ b/src/gcore/types/cloud/audit_log_entry.py @@ -0,0 +1,261 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["AuditLogEntry", "Resource", "TotalPrice"] + + +class Resource(BaseModel): + resource_id: str + """Resource ID""" + + resource_type: Literal[ + "caas_container", + "caas_key", + "caas_pull_secret", + "dbaas_postgres", + "ddos_profile", + "external_ip", + "faas_function", + "faas_key", + "faas_namespace", + "file_shares", + "floating_ip", + "gpu_baremetal_server", + "gpu_virtual_server", + "gpuai_cluster", + "image", + "inference_api_key", + "inference_application", + "inference_instance", + "inference_registry_credentials", + "inference_secret", + "instance", + "ipu_cluster", + "k8s_cluster", + "k8s_cluster_template", + "k8s_pool", + "laas", + "laas_topic", + "lb_health_monitor", + "lb_l7policy", + "lb_l7rule", + "lblistener", + "lbpool", + "lbpool_member", + "lifecycle_policy", + "lifecycle_policy_volume_member", + "loadbalancer", + "network", + "port", + "project", + "quota_limit_request", + "registry", + "registry_repository", + "registry_repository_artifact", + "registry_repository_tag", + "registry_user", + "registry_user_sercret", + "reservation", + "role", + "router", + "secret", + "securitygroup", + "securitygrouprule", + "servergroup", + "shared_flavor", + "shared_image", + "shared_network", + "snapshot", + "snapshot_schedule", + "ssh_key", + "subnet", + "token", + "user", + "virtual_gpu_cluster", + "volume", + ] + """Resource type""" + + resource_body: Optional[Dict[str, object]] = None + """Free-form object, resource body.""" + + search_field: Optional[str] = None + """Often used property for filtering actions. + + It can be a name, IP address, or other property, depending on the + `resource_type` + """ + + +class TotalPrice(BaseModel): + """Total resource price VAT inclusive""" + + currency_code: Optional[str] = None + """Currency code (3 letter code per ISO 4217)""" + + price_per_hour: Optional[float] = None + """Total price VAT inclusive per hour""" + + price_per_month: Optional[float] = None + """Total price VAT inclusive per month (30 days)""" + + price_status: Literal["error", "hide", "show"] + """Price status for the UI""" + + +class AuditLogEntry(BaseModel): + id: str + """User action ID""" + + acknowledged: bool + """ + User action log was successfully received by its subscriber in case there is one + """ + + action_data: Optional[Dict[str, object]] = None + """Additional information about the action""" + + action_type: Literal[ + "activate", + "attach", + "change_logging_resources", + "create", + "create_access_rule", + "deactivate", + "delete", + "delete_access_rule", + "delete_metadata", + "detach", + "disable_logging", + "disable_portsecurity", + "download", + "enable_logging", + "enable_portsecurity", + "failover", + "put_into_servergroup", + "reboot", + "reboot_hard", + "rebuild", + "regenerate_credentials", + "remove_from_servergroup", + "replace_metadata", + "resize", + "resume", + "retype", + "revert", + "scale_down", + "scale_up", + "start", + "stop", + "suspend", + "update", + "update_metadata", + "upgrade", + ] + """Action type""" + + api_group: Literal[ + "ai_cluster", + "caas_container", + "caas_key", + "caas_pull_secret", + "dbaas_postgres", + "ddos_profile", + "faas_function", + "faas_key", + "faas_namespace", + "file_shares", + "floating_ip", + "image", + "inference_at_the_edge", + "instance", + "instance_isolation", + "k8s_cluster", + "k8s_cluster_template", + "k8s_pool", + "laas", + "laas_topic", + "lb_health_monitor", + "lb_l7policy", + "lb_l7rule", + "lblistener", + "lbpool", + "lbpool_member", + "lifecycle_policy", + "lifecycle_policy_volume_member", + "loadbalancer", + "network", + "port", + "project", + "quota_limit_request", + "registry", + "reservation", + "reserved_fixed_ip", + "role", + "router", + "secret", + "securitygroup", + "securitygrouprule", + "servergroup", + "shared_flavor", + "shared_image", + "shared_network", + "snapshot", + "snapshot_schedule", + "ssh_key", + "subnet", + "user", + "vip_ip_addresses", + "volume", + ] + """API group""" + + client_id: Optional[int] = None + """Client ID of the user.""" + + email: Optional[str] = None + """User email address""" + + is_complete: bool + """User action was filled with all necessary information. + + If false, then something went wrong during user action creation or update + """ + + issued_by_user_id: Optional[int] = None + """User ID who issued the token that made the request""" + + project_id: Optional[int] = None + """Project ID""" + + region_id: Optional[int] = None + """Region ID""" + + resources: List[Resource] + """Resources""" + + source_user_ip: Optional[str] = None + """User IP that made the request""" + + task_id: Optional[str] = None + """Task ID""" + + timestamp: datetime + """Datetime. Action timestamp""" + + token_id: Optional[int] = None + """Token ID""" + + total_price: Optional[TotalPrice] = None + """Total resource price VAT inclusive""" + + user_agent: Optional[str] = None + """User-Agent that made the request""" + + user_id: int + """User ID""" diff --git a/src/gcore/types/cloud/audit_log_list_params.py b/src/gcore/types/cloud/audit_log_list_params.py new file mode 100644 index 00000000..337403f6 --- /dev/null +++ b/src/gcore/types/cloud/audit_log_list_params.py @@ -0,0 +1,170 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from datetime import datetime +from typing_extensions import Literal, Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = ["AuditLogListParams"] + + +class AuditLogListParams(TypedDict, total=False): + action_type: List[ + Literal[ + "activate", + "attach", + "change_logging_resources", + "create", + "create_access_rule", + "deactivate", + "delete", + "delete_access_rule", + "delete_metadata", + "detach", + "disable_logging", + "disable_portsecurity", + "download", + "enable_logging", + "enable_portsecurity", + "failover", + "put_into_servergroup", + "reboot", + "reboot_hard", + "rebuild", + "regenerate_credentials", + "remove_from_servergroup", + "replace_metadata", + "resize", + "resume", + "retype", + "revert", + "scale_down", + "scale_up", + "start", + "stop", + "suspend", + "update", + "update_metadata", + "upgrade", + ] + ] + """User action type. Several options can be specified.""" + + api_group: List[ + Literal[ + "ai_cluster", + "caas_container", + "caas_key", + "caas_pull_secret", + "dbaas_postgres", + "ddos_profile", + "faas_function", + "faas_key", + "faas_namespace", + "file_shares", + "floating_ip", + "image", + "inference_at_the_edge", + "instance", + "instance_isolation", + "k8s_cluster", + "k8s_cluster_template", + "k8s_pool", + "laas", + "laas_topic", + "lb_health_monitor", + "lb_l7policy", + "lb_l7rule", + "lblistener", + "lbpool", + "lbpool_member", + "lifecycle_policy", + "lifecycle_policy_volume_member", + "loadbalancer", + "network", + "port", + "project", + "quota_limit_request", + "registry", + "reservation", + "reserved_fixed_ip", + "role", + "router", + "secret", + "securitygroup", + "securitygrouprule", + "servergroup", + "shared_flavor", + "shared_image", + "shared_network", + "snapshot", + "snapshot_schedule", + "ssh_key", + "subnet", + "user", + "vip_ip_addresses", + "volume", + ] + ] + """API group that requested action belongs to. Several options can be specified.""" + + from_timestamp: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """ISO formatted datetime string. + + Starting timestamp from which user actions are requested + """ + + limit: int + """Optional. Limit the number of returned items""" + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ + + order_by: Literal["asc", "desc"] + """Sorting by timestamp. Oldest first, or most recent first""" + + project_id: Iterable[int] + """Project ID. Several options can be specified.""" + + region_id: Iterable[int] + """Region ID. Several options can be specified.""" + + resource_id: SequenceNotStr[str] + """Resource ID. Several options can be specified.""" + + search_field: str + """ + Extra search field for common object properties such as name, IP address, or + other, depending on the `resource_type` + """ + + sorting: Literal["asc", "desc"] + """(DEPRECATED Use 'order_by' instead) Sorting by timestamp. + + Oldest first, or most recent first + """ + + source_user_ips: SequenceNotStr[str] + """Originating IP address of the client making the request. + + Several options can be specified. + """ + + to_timestamp: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """ISO formatted datetime string. + + Ending timestamp until which user actions are requested + """ + + user_agents: SequenceNotStr[str] + """User-Agent string identifying the client making the request. + + Several options can be specified. + """ diff --git a/src/gcore/types/cloud/baremetal/__init__.py b/src/gcore/types/cloud/baremetal/__init__.py new file mode 100644 index 00000000..5c1e9aea --- /dev/null +++ b/src/gcore/types/cloud/baremetal/__init__.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .baremetal_server import BaremetalServer as BaremetalServer +from .image_list_params import ImageListParams as ImageListParams +from .flavor_list_params import FlavorListParams as FlavorListParams +from .server_list_params import ServerListParams as ServerListParams +from .server_create_params import ServerCreateParams as ServerCreateParams +from .server_rebuild_params import ServerRebuildParams as ServerRebuildParams +from .baremetal_fixed_address import BaremetalFixedAddress as BaremetalFixedAddress +from .baremetal_floating_address import BaremetalFloatingAddress as BaremetalFloatingAddress diff --git a/src/gcore/types/cloud/baremetal/baremetal_fixed_address.py b/src/gcore/types/cloud/baremetal/baremetal_fixed_address.py new file mode 100644 index 00000000..1a62ab5a --- /dev/null +++ b/src/gcore/types/cloud/baremetal/baremetal_fixed_address.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["BaremetalFixedAddress"] + + +class BaremetalFixedAddress(BaseModel): + """IP addresses of the trunk port and its subports.""" + + addr: str + """Address""" + + interface_name: Optional[str] = None + """Interface name. + + This field will be `null` if `with_interfaces_name=true` is not set in the + request when listing servers. It will also be `null` if the `interface_name` was + not specified during server creation or when attaching the interface. + """ + + subnet_id: str + """The unique identifier of the subnet associated with this address.""" + + subnet_name: str + """The name of the subnet associated with this address.""" + + type: Literal["fixed"] + """Type of the address""" diff --git a/src/gcore/types/cloud/baremetal/baremetal_floating_address.py b/src/gcore/types/cloud/baremetal/baremetal_floating_address.py new file mode 100644 index 00000000..a5690da4 --- /dev/null +++ b/src/gcore/types/cloud/baremetal/baremetal_floating_address.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["BaremetalFloatingAddress"] + + +class BaremetalFloatingAddress(BaseModel): + addr: str + """Address""" + + type: Literal["floating"] + """Type of the address""" diff --git a/src/gcore/types/cloud/baremetal/baremetal_server.py b/src/gcore/types/cloud/baremetal/baremetal_server.py new file mode 100644 index 00000000..1c3e9a8f --- /dev/null +++ b/src/gcore/types/cloud/baremetal/baremetal_server.py @@ -0,0 +1,182 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, TypeAlias + +from ..tag import Tag +from ...._models import BaseModel +from ..ddos_profile import DDOSProfile +from ..blackhole_port import BlackholePort +from ..instance_isolation import InstanceIsolation +from .baremetal_fixed_address import BaremetalFixedAddress +from .baremetal_floating_address import BaremetalFloatingAddress + +__all__ = ["BaremetalServer", "Address", "FixedIPAssignment", "Flavor", "FlavorHardwareDescription"] + +Address: TypeAlias = Union[BaremetalFloatingAddress, BaremetalFixedAddress] + + +class FixedIPAssignment(BaseModel): + external: bool + """Is network external""" + + ip_address: str + """Ip address""" + + subnet_id: str + """Interface subnet id""" + + +class FlavorHardwareDescription(BaseModel): + """Additional hardware description""" + + cpu: str + """Human-readable CPU description""" + + disk: str + """Human-readable disk description""" + + license: str + """If the flavor is licensed, this field contains the license type""" + + network: str + """Human-readable NIC description""" + + ram: str + """Human-readable RAM description""" + + +class Flavor(BaseModel): + """Flavor details""" + + architecture: str + """CPU architecture""" + + flavor_id: str + """Flavor ID is the same as name""" + + flavor_name: str + """Flavor name""" + + hardware_description: FlavorHardwareDescription + """Additional hardware description""" + + os_type: str + """Operating system""" + + ram: int + """RAM size in MiB""" + + resource_class: str + """Flavor resource class for mapping to hardware capacity""" + + vcpus: int + """Virtual CPU count. For bare metal flavors, it's a physical CPU count""" + + +class BaremetalServer(BaseModel): + id: str + """Bare metal server ID""" + + addresses: Dict[str, List[Address]] + """Map of `network_name` to list of addresses in that network""" + + blackhole_ports: List[BlackholePort] + """IP addresses of the instances that are blackholed by DDoS mitigation system""" + + created_at: datetime + """Datetime when bare metal server was created""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + ddos_profile: Optional[DDOSProfile] = None + """Bare metal advanced DDoS protection profile. + + It is always `null` if query parameter `with_ddos=true` is not set. + """ + + fixed_ip_assignments: List[FixedIPAssignment] + """Fixed IP assigned to instance""" + + flavor: Flavor + """Flavor details""" + + instance_isolation: Optional[InstanceIsolation] = None + """Instance isolation information""" + + name: str + """Bare metal server name""" + + project_id: int + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + ssh_key_name: Optional[str] = None + """SSH key assigned to bare metal server""" + + status: Literal[ + "ACTIVE", + "BUILD", + "DELETED", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PASSWORD", + "PAUSED", + "REBOOT", + "REBUILD", + "RESCUE", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "UNKNOWN", + "VERIFY_RESIZE", + ] + """Bare metal server status""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + task_state: Optional[str] = None + """Task state""" + + vm_state: Literal[ + "active", + "building", + "deleted", + "error", + "paused", + "rescued", + "resized", + "shelved", + "shelved_offloaded", + "soft-deleted", + "stopped", + "suspended", + ] + """Bare metal server state""" diff --git a/src/gcore/types/cloud/baremetal/flavor_list_params.py b/src/gcore/types/cloud/baremetal/flavor_list_params.py new file mode 100644 index 00000000..618ab77f --- /dev/null +++ b/src/gcore/types/cloud/baremetal/flavor_list_params.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["FlavorListParams"] + + +class FlavorListParams(TypedDict, total=False): + project_id: int + + region_id: int + + disabled: bool + """Flag for filtering disabled flavors in the region. Defaults to true""" + + exclude_linux: bool + """Set to true to exclude flavors dedicated to linux images. Default False""" + + exclude_windows: bool + """Set to true to exclude flavors dedicated to windows images. Default False""" + + include_capacity: bool + """Set to true if the response should include flavor capacity""" + + include_prices: bool + """Set to true if the response should include flavor prices""" + + include_reservation_stock: bool + """Optional. + + Set to true if flavor listing should include count of reserved resources in + stock. + """ diff --git a/src/gcore/types/cloud/baremetal/image_list_params.py b/src/gcore/types/cloud/baremetal/image_list_params.py new file mode 100644 index 00000000..1e1d2903 --- /dev/null +++ b/src/gcore/types/cloud/baremetal/image_list_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["ImageListParams"] + + +class ImageListParams(TypedDict, total=False): + project_id: int + + region_id: int + + include_prices: bool + """Show price""" + + private: str + """Any value to show private images""" + + tag_key: SequenceNotStr[str] + """Filter by tag keys.""" + + tag_key_value: str + """Filter by tag key-value pairs. Must be a valid JSON string.""" + + visibility: Literal["private", "public", "shared"] + """Image visibility. Globally visible images are public""" diff --git a/src/gcore/types/cloud/baremetal/server_create_params.py b/src/gcore/types/cloud/baremetal/server_create_params.py new file mode 100644 index 00000000..08280551 --- /dev/null +++ b/src/gcore/types/cloud/baremetal/server_create_params.py @@ -0,0 +1,378 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..interface_ip_family import InterfaceIPFamily + +__all__ = [ + "ServerCreateParams", + "Interface", + "InterfaceCreateBareMetalExternalInterfaceSerializer", + "InterfaceCreateBareMetalSubnetInterfaceSerializer", + "InterfaceCreateBareMetalSubnetInterfaceSerializerFloatingIP", + "InterfaceCreateBareMetalSubnetInterfaceSerializerFloatingIPNewInstanceFloatingIPInterfaceSerializer", + "InterfaceCreateBareMetalSubnetInterfaceSerializerFloatingIPExistingInstanceFloatingIPInterfaceSerializer", + "InterfaceCreateBareMetalAnySubnetInterfaceSerializer", + "InterfaceCreateBareMetalAnySubnetInterfaceSerializerFloatingIP", + "InterfaceCreateBareMetalAnySubnetInterfaceSerializerFloatingIPNewInstanceFloatingIPInterfaceSerializer", + "InterfaceCreateBareMetalAnySubnetInterfaceSerializerFloatingIPExistingInstanceFloatingIPInterfaceSerializer", + "InterfaceCreateBareMetalReservedFixedIPInterfaceSerializer", + "InterfaceCreateBareMetalReservedFixedIPInterfaceSerializerFloatingIP", + "InterfaceCreateBareMetalReservedFixedIPInterfaceSerializerFloatingIPNewInstanceFloatingIPInterfaceSerializer", + "InterfaceCreateBareMetalReservedFixedIPInterfaceSerializerFloatingIPExistingInstanceFloatingIPInterfaceSerializer", + "DDOSProfile", + "DDOSProfileField", +] + + +class ServerCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + flavor: Required[str] + """The flavor of the instance.""" + + interfaces: Required[Iterable[Interface]] + """A list of network interfaces for the server. + + You can create one or more interfaces - private, public, or both. + """ + + app_config: Optional[Dict[str, object]] + """ + Parameters for the application template if creating the instance from an + `apptemplate`. + """ + + apptemplate_id: str + """Apptemplate ID. Either `image_id` or `apptemplate_id` is required.""" + + ddos_profile: DDOSProfile + """Enable advanced DDoS protection for the server""" + + image_id: str + """Image ID. Either `image_id` or `apptemplate_id` is required.""" + + name: str + """Server name.""" + + name_template: str + """ + If you want server names to be automatically generated based on IP addresses, + you can provide a name template instead of specifying the name manually. The + template should include a placeholder that will be replaced during provisioning. + Supported placeholders are: `{ip_octets}` (last 3 octets of the IP), + `{two_ip_octets}`, and `{one_ip_octet}`. + """ + + password: str + """For Linux instances, 'username' and 'password' are used to create a new user. + + When only 'password' is provided, it is set as the password for the default user + of the image. For Windows instances, 'username' cannot be specified. Use the + 'password' field to set the password for the 'Admin' user on Windows. Use the + 'user_data' field to provide a script to create new users on Windows. The + password of the Admin user cannot be updated via 'user_data'. + """ + + ssh_key_name: Optional[str] + """ + Specifies the name of the SSH keypair, created via the + [/v1/`ssh_keys` endpoint](/docs/api-reference/cloud/ssh-keys/add-or-generate-ssh-key). + """ + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + user_data: str + """String in base64 format. + + For Linux instances, 'user_data' is ignored when 'password' field is provided. + For Windows instances, Admin user password is set by 'password' field and cannot + be updated via 'user_data'. Examples of the `user_data`: + https://cloudinit.readthedocs.io/en/latest/topics/examples.html + """ + + username: str + """For Linux instances, 'username' and 'password' are used to create a new user. + + For Windows instances, 'username' cannot be specified. Use 'password' field to + set the password for the 'Admin' user on Windows. + """ + + +class InterfaceCreateBareMetalExternalInterfaceSerializer(TypedDict, total=False): + """Instance will be attached to default external network""" + + type: Required[Literal["external"]] + """A public IP address will be assigned to the instance.""" + + interface_name: str + """Interface name. + + Defaults to `null` and is returned as `null` in the API response if not set. + """ + + ip_family: Optional[InterfaceIPFamily] + """Specify `ipv4`, `ipv6`, or `dual` to enable both.""" + + port_group: int + """Specifies the trunk group to which this interface belongs. + + Applicable only for bare metal servers. Each unique port group is mapped to a + separate trunk port. Use this to control how interfaces are grouped across + trunks. + """ + + +class InterfaceCreateBareMetalSubnetInterfaceSerializerFloatingIPNewInstanceFloatingIPInterfaceSerializer( + TypedDict, total=False +): + source: Required[Literal["new"]] + """A new floating IP will be created and attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +class InterfaceCreateBareMetalSubnetInterfaceSerializerFloatingIPExistingInstanceFloatingIPInterfaceSerializer( + TypedDict, total=False +): + existing_floating_id: Required[str] + """ + An existing available floating IP id must be specified if the source is set to + `existing` + """ + + source: Required[Literal["existing"]] + """An existing available floating IP will be attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +InterfaceCreateBareMetalSubnetInterfaceSerializerFloatingIP: TypeAlias = Union[ + InterfaceCreateBareMetalSubnetInterfaceSerializerFloatingIPNewInstanceFloatingIPInterfaceSerializer, + InterfaceCreateBareMetalSubnetInterfaceSerializerFloatingIPExistingInstanceFloatingIPInterfaceSerializer, +] + + +class InterfaceCreateBareMetalSubnetInterfaceSerializer(TypedDict, total=False): + """ + The instance will get an IP address from the selected network. + If you choose to add a floating IP, the instance will be reachable from the internet. + Otherwise, it will only have a private IP within the network. + """ + + network_id: Required[str] + """The network where the instance will be connected.""" + + subnet_id: Required[str] + """The instance will get an IP address from this subnet.""" + + type: Required[Literal["subnet"]] + """The instance will get an IP address from the selected network. + + If you choose to add a floating IP, the instance will be reachable from the + internet. Otherwise, it will only have a private IP within the network. + """ + + floating_ip: InterfaceCreateBareMetalSubnetInterfaceSerializerFloatingIP + """Allows the instance to have a public IP that can be reached from the internet.""" + + interface_name: str + """Interface name. + + Defaults to `null` and is returned as `null` in the API response if not set. + """ + + port_group: int + """Specifies the trunk group to which this interface belongs. + + Applicable only for bare metal servers. Each unique port group is mapped to a + separate trunk port. Use this to control how interfaces are grouped across + trunks. + """ + + +class InterfaceCreateBareMetalAnySubnetInterfaceSerializerFloatingIPNewInstanceFloatingIPInterfaceSerializer( + TypedDict, total=False +): + source: Required[Literal["new"]] + """A new floating IP will be created and attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +class InterfaceCreateBareMetalAnySubnetInterfaceSerializerFloatingIPExistingInstanceFloatingIPInterfaceSerializer( + TypedDict, total=False +): + existing_floating_id: Required[str] + """ + An existing available floating IP id must be specified if the source is set to + `existing` + """ + + source: Required[Literal["existing"]] + """An existing available floating IP will be attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +InterfaceCreateBareMetalAnySubnetInterfaceSerializerFloatingIP: TypeAlias = Union[ + InterfaceCreateBareMetalAnySubnetInterfaceSerializerFloatingIPNewInstanceFloatingIPInterfaceSerializer, + InterfaceCreateBareMetalAnySubnetInterfaceSerializerFloatingIPExistingInstanceFloatingIPInterfaceSerializer, +] + + +class InterfaceCreateBareMetalAnySubnetInterfaceSerializer(TypedDict, total=False): + network_id: Required[str] + """The network where the instance will be connected.""" + + type: Required[Literal["any_subnet"]] + """Instance will be attached to a subnet with the largest count of free IPs.""" + + floating_ip: InterfaceCreateBareMetalAnySubnetInterfaceSerializerFloatingIP + """Allows the instance to have a public IP that can be reached from the internet.""" + + interface_name: str + """Interface name. + + Defaults to `null` and is returned as `null` in the API response if not set. + """ + + ip_address: str + """You can specify a specific IP address from your subnet.""" + + ip_family: Optional[InterfaceIPFamily] + """Specify `ipv4`, `ipv6`, or `dual` to enable both.""" + + port_group: int + """Specifies the trunk group to which this interface belongs. + + Applicable only for bare metal servers. Each unique port group is mapped to a + separate trunk port. Use this to control how interfaces are grouped across + trunks. + """ + + +class InterfaceCreateBareMetalReservedFixedIPInterfaceSerializerFloatingIPNewInstanceFloatingIPInterfaceSerializer( + TypedDict, total=False +): + source: Required[Literal["new"]] + """A new floating IP will be created and attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +class InterfaceCreateBareMetalReservedFixedIPInterfaceSerializerFloatingIPExistingInstanceFloatingIPInterfaceSerializer( + TypedDict, total=False +): + existing_floating_id: Required[str] + """ + An existing available floating IP id must be specified if the source is set to + `existing` + """ + + source: Required[Literal["existing"]] + """An existing available floating IP will be attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +InterfaceCreateBareMetalReservedFixedIPInterfaceSerializerFloatingIP: TypeAlias = Union[ + InterfaceCreateBareMetalReservedFixedIPInterfaceSerializerFloatingIPNewInstanceFloatingIPInterfaceSerializer, + InterfaceCreateBareMetalReservedFixedIPInterfaceSerializerFloatingIPExistingInstanceFloatingIPInterfaceSerializer, +] + + +class InterfaceCreateBareMetalReservedFixedIPInterfaceSerializer(TypedDict, total=False): + port_id: Required[str] + """Network ID the subnet belongs to. Port will be plugged in this network.""" + + type: Required[Literal["reserved_fixed_ip"]] + """An existing available reserved fixed IP will be attached to the instance. + + If the reserved IP is not public and you choose to add a floating IP, the + instance will be accessible from the internet. + """ + + floating_ip: InterfaceCreateBareMetalReservedFixedIPInterfaceSerializerFloatingIP + """Allows the instance to have a public IP that can be reached from the internet.""" + + interface_name: str + """Interface name. + + Defaults to `null` and is returned as `null` in the API response if not set. + """ + + port_group: int + """Specifies the trunk group to which this interface belongs. + + Applicable only for bare metal servers. Each unique port group is mapped to a + separate trunk port. Use this to control how interfaces are grouped across + trunks. + """ + + +Interface: TypeAlias = Union[ + InterfaceCreateBareMetalExternalInterfaceSerializer, + InterfaceCreateBareMetalSubnetInterfaceSerializer, + InterfaceCreateBareMetalAnySubnetInterfaceSerializer, + InterfaceCreateBareMetalReservedFixedIPInterfaceSerializer, +] + + +class DDOSProfileField(TypedDict, total=False): + base_field: Optional[int] + """Unique identifier of the DDoS protection field being configured""" + + field_name: Optional[str] + """Human-readable name of the DDoS protection field being configured""" + + field_value: object + + value: Optional[str] + """Basic type value. Only one of 'value' or 'field_value' must be specified.""" + + +class DDOSProfile(TypedDict, total=False): + """Enable advanced DDoS protection for the server""" + + profile_template: Required[int] + """Unique identifier of the DDoS protection template to use for this profile""" + + fields: Iterable[DDOSProfileField] + """ + List of field configurations that customize the protection parameters for this + profile + """ diff --git a/src/gcore/types/cloud/baremetal/server_list_params.py b/src/gcore/types/cloud/baremetal/server_list_params.py new file mode 100644 index 00000000..75547dff --- /dev/null +++ b/src/gcore/types/cloud/baremetal/server_list_params.py @@ -0,0 +1,111 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Literal, Annotated, TypedDict + +from ...._types import SequenceNotStr +from ...._utils import PropertyInfo + +__all__ = ["ServerListParams"] + + +class ServerListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + changes_before: Annotated[Union[str, datetime], PropertyInfo(alias="changes-before", format="iso8601")] + """Filters the instances by a date and time stamp when the instances last changed.""" + + changes_since: Annotated[Union[str, datetime], PropertyInfo(alias="changes-since", format="iso8601")] + """ + Filters the instances by a date and time stamp when the instances last changed + status. + """ + + flavor_id: str + """Filter out instances by `flavor_id`. Flavor id must match exactly.""" + + flavor_prefix: str + """Filter out instances by `flavor_prefix`.""" + + include_k8s: bool + """Include managed k8s worker nodes""" + + ip: str + """An IPv4 address to filter results by. + + Note: partial matches are allowed. For example, searching for 192.168.0.1 will + return 192.168.0.1, 192.168.0.10, 192.168.0.110, and so on. + """ + + limit: int + """Optional. Limit the number of returned items""" + + name: str + """Filter instances by name. + + You can provide a full or partial name, instances with matching names will be + returned. For example, entering 'test' will return all instances that contain + 'test' in their name. + """ + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ + + only_isolated: bool + """Include only isolated instances""" + + only_with_fixed_external_ip: bool + """Return bare metals only with external fixed IP addresses.""" + + order_by: Literal["created.asc", "created.desc", "name.asc", "name.desc", "status.asc", "status.desc"] + """Order by field and direction.""" + + profile_name: str + """Filter result by ddos protection profile name. + + Effective only with `with_ddos` set to true. + """ + + protection_status: Literal["Active", "Queued", "Error"] + """Filter result by DDoS `protection_status`. + + Effective only with `with_ddos` set to true. (Active, Queued or Error) + """ + + status: Literal["ACTIVE", "BUILD", "ERROR", "HARD_REBOOT", "REBOOT", "REBUILD", "RESCUE", "SHUTOFF", "SUSPENDED"] + """Filters instances by a server status, as a string.""" + + tag_key_value: str + """Optional. Filter by tag key-value pairs.""" + + tag_value: SequenceNotStr[str] + """Optional. Filter by tag values. ?`tag_value`=value1&`tag_value`=value2""" + + type_ddos_profile: Literal["basic", "advanced"] + """Return bare metals either only with advanced or only basic DDoS protection. + + Effective only with `with_ddos` set to true. (advanced or basic) + """ + + uuid: str + """Filter the server list result by the UUID of the server. Allowed UUID part""" + + with_ddos: bool + """ + Include DDoS profile information for bare-metal servers in the response when set + to `true`. Otherwise, the `ddos_profile` field in the response is `null` by + default. + """ + + with_interfaces_name: bool + """Include `interface_name` in the addresses""" diff --git a/src/gcore/types/cloud/baremetal/server_rebuild_params.py b/src/gcore/types/cloud/baremetal/server_rebuild_params.py new file mode 100644 index 00000000..9addcb49 --- /dev/null +++ b/src/gcore/types/cloud/baremetal/server_rebuild_params.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ServerRebuildParams"] + + +class ServerRebuildParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + image_id: str + """Image ID""" + + user_data: str + """String in base64 format. + + Must not be passed together with 'username' or 'password'. Examples of the + `user_data`: https://cloudinit.readthedocs.io/en/latest/topics/examples.html + """ diff --git a/src/gcore/types/cloud/baremetal_flavor.py b/src/gcore/types/cloud/baremetal_flavor.py new file mode 100644 index 00000000..7a1152f9 --- /dev/null +++ b/src/gcore/types/cloud/baremetal_flavor.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["BaremetalFlavor"] + + +class BaremetalFlavor(BaseModel): + """Bare metal flavor schema""" + + architecture: str + """Flavor architecture type""" + + disabled: bool + """Disabled flavor flag""" + + flavor_id: str + """Flavor ID is the same as name""" + + flavor_name: str + """Flavor name""" + + os_type: str + """Flavor operating system""" + + ram: int + """RAM size in MiB""" + + resource_class: Optional[str] = None + """Flavor resource class for mapping to hardware capacity""" + + vcpus: int + """Virtual CPU count. For bare metal flavors, it's a physical CPU count""" + + capacity: Optional[int] = None + """Number of available instances of given configuration""" + + currency_code: Optional[str] = None + """Currency code. Shown if the `include_prices` query parameter if set to true""" + + hardware_description: Optional[Dict[str, str]] = None + """Additional hardware description""" + + price_per_hour: Optional[float] = None + """Price per hour. Shown if the `include_prices` query parameter if set to true""" + + price_per_month: Optional[float] = None + """Price per month. Shown if the `include_prices` query parameter if set to true""" + + price_status: Optional[Literal["error", "hide", "show"]] = None + """Price status for the UI""" + + reserved_capacity: Optional[int] = None + """Number of available instances of given flavor from reservations""" diff --git a/src/gcore/types/cloud/baremetal_flavor_list.py b/src/gcore/types/cloud/baremetal_flavor_list.py new file mode 100644 index 00000000..f57c96ec --- /dev/null +++ b/src/gcore/types/cloud/baremetal_flavor_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .baremetal_flavor import BaremetalFlavor + +__all__ = ["BaremetalFlavorList"] + + +class BaremetalFlavorList(BaseModel): + count: int + """Number of objects""" + + results: List[BaremetalFlavor] + """Objects""" diff --git a/src/gcore/types/cloud/billing_reservation.py b/src/gcore/types/cloud/billing_reservation.py new file mode 100644 index 00000000..9800c029 --- /dev/null +++ b/src/gcore/types/cloud/billing_reservation.py @@ -0,0 +1,97 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["BillingReservation", "ActiveOvercommit", "Commit", "HardwareInfo"] + + +class ActiveOvercommit(BaseModel): + """Overcommit pricing details""" + + active_from: datetime + """Billing subscription active from date""" + + plan_item_id: Optional[int] = None + """Billing plan item ID""" + + price_per_month: str + """Price per month""" + + price_per_unit: str + """Price per unit (hourly)""" + + price_total: str + """Total price for the reservation period""" + + subscription_id: Optional[int] = None + """Billing subscription ID for overcommit""" + + +class Commit(BaseModel): + """Commit pricing details""" + + active_from: datetime + """Billing subscription active from date""" + + active_to: Optional[datetime] = None + """Billing subscription active to date""" + + price_per_month: str + """Price per month, per one resource""" + + price_per_unit: str + """Price per unit, per one resource (hourly)""" + + price_total: str + """Total price for the reservation period for the full reserved amount""" + + subscription_id: int + """Billing subscription ID for commit""" + + +class HardwareInfo(BaseModel): + """Hardware specifications""" + + cpu: Optional[str] = None + """CPU specification""" + + disk: Optional[str] = None + """Disk specification""" + + ram: Optional[str] = None + """RAM specification""" + + +class BillingReservation(BaseModel): + active_billing_plan_id: int + """Active billing plan ID""" + + active_overcommit: ActiveOvercommit + """Overcommit pricing details""" + + commit: Commit + """Commit pricing details""" + + hardware_info: HardwareInfo + """Hardware specifications""" + + region_name: str + """Region name""" + + resource_count: int + """Number of reserved resource items""" + + resource_name: str + """Resource name""" + + unit_name: str + """Unit name (e.g., 'H' for hours)""" + + unit_size_month: str + """Unit size per month (e.g., 744 hours)""" + + unit_size_total: str + """Unit size month multiplied by count of resources in the reservation""" diff --git a/src/gcore/types/cloud/billing_reservation_list_params.py b/src/gcore/types/cloud/billing_reservation_list_params.py new file mode 100644 index 00000000..3142e04f --- /dev/null +++ b/src/gcore/types/cloud/billing_reservation_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["BillingReservationListParams"] + + +class BillingReservationListParams(TypedDict, total=False): + metric_name: str + """Metric name for the resource (e.g., 'bm1-hf-medium_min')""" + + order_by: Literal["active_from.asc", "active_from.desc", "active_to.asc", "active_to.desc"] + """Order by field and direction.""" + + region_id: int + """Region for reservation""" + + show_inactive: bool + """Include inactive commits in the response""" diff --git a/src/gcore/types/cloud/billing_reservations.py b/src/gcore/types/cloud/billing_reservations.py new file mode 100644 index 00000000..d3787fba --- /dev/null +++ b/src/gcore/types/cloud/billing_reservations.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .billing_reservation import BillingReservation + +__all__ = ["BillingReservations"] + + +class BillingReservations(BaseModel): + count: int + """Number of objects""" + + results: List[BillingReservation] + """Objects""" diff --git a/src/gcore/types/cloud/blackhole_port.py b/src/gcore/types/cloud/blackhole_port.py new file mode 100644 index 00000000..8586ddc3 --- /dev/null +++ b/src/gcore/types/cloud/blackhole_port.py @@ -0,0 +1,69 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["BlackholePort"] + + +class BlackholePort(BaseModel): + alarm_end: datetime = FieldInfo(alias="AlarmEnd") + """A date-time string giving the time that the alarm ended. + + If not yet ended, time will be given as 0001-01-01T00:00:00Z + """ + + alarm_start: datetime = FieldInfo(alias="AlarmStart") + """A date-time string giving the time that the alarm started""" + + alarm_state: Literal[ + "ACK_REQ", + "ALARM", + "ARCHIVED", + "CLEAR", + "CLEARING", + "CLEARING_FAIL", + "END_GRACE", + "END_WAIT", + "MANUAL_CLEAR", + "MANUAL_CLEARING", + "MANUAL_CLEARING_FAIL", + "MANUAL_MITIGATING", + "MANUAL_STARTING", + "MANUAL_STARTING_FAIL", + "MITIGATING", + "STARTING", + "STARTING_FAIL", + "START_WAIT", + "ack_req", + "alarm", + "archived", + "clear", + "clearing", + "clearing_fail", + "end_grace", + "end_wait", + "manual_clear", + "manual_clearing", + "manual_clearing_fail", + "manual_mitigating", + "manual_starting", + "manual_starting_fail", + "mitigating", + "start_wait", + "starting", + "starting_fail", + ] = FieldInfo(alias="AlarmState") + """Current state of alarm""" + + alert_duration: str = FieldInfo(alias="AlertDuration") + """Total alert duration""" + + destination_ip: str = FieldInfo(alias="DestinationIP") + """Notification destination IP address""" + + id: int = FieldInfo(alias="ID") diff --git a/src/gcore/types/cloud/console.py b/src/gcore/types/cloud/console.py new file mode 100644 index 00000000..76eab309 --- /dev/null +++ b/src/gcore/types/cloud/console.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["Console", "RemoteConsole"] + + +class RemoteConsole(BaseModel): + """Remote console information""" + + protocol: str + + type: str + + url: str + + +class Console(BaseModel): + remote_console: RemoteConsole + """Remote console information""" diff --git a/src/gcore/types/cloud/cost_report_aggregated.py b/src/gcore/types/cloud/cost_report_aggregated.py new file mode 100644 index 00000000..4697169e --- /dev/null +++ b/src/gcore/types/cloud/cost_report_aggregated.py @@ -0,0 +1,865 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "CostReportAggregated", + "Result", + "ResultTotalAIClusterWithCostSerializer", + "ResultTotalAIVirtualClusterWithCostSerializer", + "ResultTotalBaremetalWithCostSerializer", + "ResultTotalBasicVmWithCostSerializer", + "ResultTotalBackupWithCostSerializer", + "ResultTotalContainerWithCostSerializer", + "ResultTotalEgressTrafficWithCostSerializer", + "ResultTotalExternalIPWithCostSerializer", + "ResultTotalFileShareWithCostSerializer", + "ResultTotalFloatingIPWithCostSerializer", + "ResultTotalFunctionsWithCostSerializer", + "ResultTotalFunctionCallsWithCostSerializer", + "ResultTotalFunctionEgressTrafficWithCostSerializer", + "ResultTotalImagesWithCostSerializer", + "ResultTotalInferenceWithCostSerializer", + "ResultTotalInstanceWithCostSerializer", + "ResultTotalLoadBalancerWithCostSerializer", + "ResultTotalLogIndexWithCostSerializer", + "ResultTotalSnapshotWithCostSerializer", + "ResultTotalVolumeWithCostSerializer", + "ResultTotalDbaasPostgreSQLPoolerWithCostSerializer", + "ResultTotalDbaasPostgreSQLMemoryWithCostSerializer", + "ResultTotalDbaasPostgreSQLPublicNetworkWithCostSerializer", + "ResultTotalDbaasPostgreSqlcpuWithCostSerializer", + "ResultTotalDbaasPostgreSQLVolumeWithCostSerializer", +] + + +class ResultTotalAIClusterWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + flavor: str + """Flavor of the Baremetal GPU cluster""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["ai_cluster"] + + +class ResultTotalAIVirtualClusterWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + flavor: str + """Flavor of the Virtual GPU cluster""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["ai_virtual_cluster"] + + +class ResultTotalBaremetalWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + flavor: str + """Flavor of the bare metal server""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["baremetal"] + + +class ResultTotalBasicVmWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + flavor: str + """Flavor of the basic VM""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["basic_vm"] + + +class ResultTotalBackupWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + last_size: int + """Size of the backup in bytes""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["backup"] + + +class ResultTotalContainerWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GBS"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["containers"] + + +class ResultTotalEgressTrafficWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["bytes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + instance_type: Literal["baremetal", "vm"] + """Type of the instance""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["egress_traffic"] + + +class ResultTotalExternalIPWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["external_ip"] + + +class ResultTotalFileShareWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + file_share_type: str + """Type of the file share""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["file_share"] + + +class ResultTotalFloatingIPWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["floatingip"] + + +class ResultTotalFunctionsWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GBS"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions"] + + +class ResultTotalFunctionCallsWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["MLS"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions_calls"] + + +class ResultTotalFunctionEgressTrafficWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GB"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions_traffic"] + + +class ResultTotalImagesWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["image"] + + +class ResultTotalInferenceWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: str + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["inference"] + + +class ResultTotalInstanceWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + flavor: str + """Flavor of the instance""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["instance"] + + +class ResultTotalLoadBalancerWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + flavor: str + """Flavor of the load balancer""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["load_balancer"] + + +class ResultTotalLogIndexWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["log_index"] + + +class ResultTotalSnapshotWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["snapshot"] + + volume_type: str + """Type of the volume""" + + +class ResultTotalVolumeWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["volume"] + + volume_type: str + """Type of the volume""" + + +class ResultTotalDbaasPostgreSQLPoolerWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_connection_pooler"] + + +class ResultTotalDbaasPostgreSQLMemoryWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_memory"] + + +class ResultTotalDbaasPostgreSQLPublicNetworkWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_public_network"] + + +class ResultTotalDbaasPostgreSqlcpuWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_cpu"] + + +class ResultTotalDbaasPostgreSQLVolumeWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_volume"] + + volume_type: str + """Type of the volume""" + + +Result: TypeAlias = Annotated[ + Union[ + ResultTotalAIClusterWithCostSerializer, + ResultTotalAIVirtualClusterWithCostSerializer, + ResultTotalBaremetalWithCostSerializer, + ResultTotalBasicVmWithCostSerializer, + ResultTotalBackupWithCostSerializer, + ResultTotalContainerWithCostSerializer, + ResultTotalEgressTrafficWithCostSerializer, + ResultTotalExternalIPWithCostSerializer, + ResultTotalFileShareWithCostSerializer, + ResultTotalFloatingIPWithCostSerializer, + ResultTotalFunctionsWithCostSerializer, + ResultTotalFunctionCallsWithCostSerializer, + ResultTotalFunctionEgressTrafficWithCostSerializer, + ResultTotalImagesWithCostSerializer, + ResultTotalInferenceWithCostSerializer, + ResultTotalInstanceWithCostSerializer, + ResultTotalLoadBalancerWithCostSerializer, + ResultTotalLogIndexWithCostSerializer, + ResultTotalSnapshotWithCostSerializer, + ResultTotalVolumeWithCostSerializer, + ResultTotalDbaasPostgreSQLPoolerWithCostSerializer, + ResultTotalDbaasPostgreSQLMemoryWithCostSerializer, + ResultTotalDbaasPostgreSQLPublicNetworkWithCostSerializer, + ResultTotalDbaasPostgreSqlcpuWithCostSerializer, + ResultTotalDbaasPostgreSQLVolumeWithCostSerializer, + ], + PropertyInfo(discriminator="type"), +] + + +class CostReportAggregated(BaseModel): + count: int + """Count of returned totals""" + + price_status: Literal["error", "hide", "show"] + """Price status for the UI, type: string""" + + results: List[Result] diff --git a/src/gcore/types/cloud/cost_report_aggregated_monthly.py b/src/gcore/types/cloud/cost_report_aggregated_monthly.py new file mode 100644 index 00000000..d62de86d --- /dev/null +++ b/src/gcore/types/cloud/cost_report_aggregated_monthly.py @@ -0,0 +1,865 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "CostReportAggregatedMonthly", + "Result", + "ResultTotalAIClusterWithCostSerializer", + "ResultTotalAIVirtualClusterWithCostSerializer", + "ResultTotalBaremetalWithCostSerializer", + "ResultTotalBasicVmWithCostSerializer", + "ResultTotalBackupWithCostSerializer", + "ResultTotalContainerWithCostSerializer", + "ResultTotalEgressTrafficWithCostSerializer", + "ResultTotalExternalIPWithCostSerializer", + "ResultTotalFileShareWithCostSerializer", + "ResultTotalFloatingIPWithCostSerializer", + "ResultTotalFunctionsWithCostSerializer", + "ResultTotalFunctionCallsWithCostSerializer", + "ResultTotalFunctionEgressTrafficWithCostSerializer", + "ResultTotalImagesWithCostSerializer", + "ResultTotalInferenceWithCostSerializer", + "ResultTotalInstanceWithCostSerializer", + "ResultTotalLoadBalancerWithCostSerializer", + "ResultTotalLogIndexWithCostSerializer", + "ResultTotalSnapshotWithCostSerializer", + "ResultTotalVolumeWithCostSerializer", + "ResultTotalDbaasPostgreSQLPoolerWithCostSerializer", + "ResultTotalDbaasPostgreSQLMemoryWithCostSerializer", + "ResultTotalDbaasPostgreSQLPublicNetworkWithCostSerializer", + "ResultTotalDbaasPostgreSqlcpuWithCostSerializer", + "ResultTotalDbaasPostgreSQLVolumeWithCostSerializer", +] + + +class ResultTotalAIClusterWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + flavor: str + """Flavor of the Baremetal GPU cluster""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["ai_cluster"] + + +class ResultTotalAIVirtualClusterWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + flavor: str + """Flavor of the Virtual GPU cluster""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["ai_virtual_cluster"] + + +class ResultTotalBaremetalWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + flavor: str + """Flavor of the bare metal server""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["baremetal"] + + +class ResultTotalBasicVmWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + flavor: str + """Flavor of the basic VM""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["basic_vm"] + + +class ResultTotalBackupWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + last_size: int + """Size of the backup in bytes""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["backup"] + + +class ResultTotalContainerWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GBS"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["containers"] + + +class ResultTotalEgressTrafficWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["bytes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + instance_type: Literal["baremetal", "vm"] + """Type of the instance""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["egress_traffic"] + + +class ResultTotalExternalIPWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["external_ip"] + + +class ResultTotalFileShareWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + file_share_type: str + """Type of the file share""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["file_share"] + + +class ResultTotalFloatingIPWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["floatingip"] + + +class ResultTotalFunctionsWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GBS"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions"] + + +class ResultTotalFunctionCallsWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["MLS"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions_calls"] + + +class ResultTotalFunctionEgressTrafficWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GB"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions_traffic"] + + +class ResultTotalImagesWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["image"] + + +class ResultTotalInferenceWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: str + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["inference"] + + +class ResultTotalInstanceWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + flavor: str + """Flavor of the instance""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["instance"] + + +class ResultTotalLoadBalancerWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + flavor: str + """Flavor of the load balancer""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["load_balancer"] + + +class ResultTotalLogIndexWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["log_index"] + + +class ResultTotalSnapshotWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["snapshot"] + + volume_type: str + """Type of the volume""" + + +class ResultTotalVolumeWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["volume"] + + volume_type: str + """Type of the volume""" + + +class ResultTotalDbaasPostgreSQLPoolerWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_connection_pooler"] + + +class ResultTotalDbaasPostgreSQLMemoryWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_memory"] + + +class ResultTotalDbaasPostgreSQLPublicNetworkWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_public_network"] + + +class ResultTotalDbaasPostgreSqlcpuWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_cpu"] + + +class ResultTotalDbaasPostgreSQLVolumeWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_volume"] + + volume_type: str + """Type of the volume""" + + +Result: TypeAlias = Annotated[ + Union[ + ResultTotalAIClusterWithCostSerializer, + ResultTotalAIVirtualClusterWithCostSerializer, + ResultTotalBaremetalWithCostSerializer, + ResultTotalBasicVmWithCostSerializer, + ResultTotalBackupWithCostSerializer, + ResultTotalContainerWithCostSerializer, + ResultTotalEgressTrafficWithCostSerializer, + ResultTotalExternalIPWithCostSerializer, + ResultTotalFileShareWithCostSerializer, + ResultTotalFloatingIPWithCostSerializer, + ResultTotalFunctionsWithCostSerializer, + ResultTotalFunctionCallsWithCostSerializer, + ResultTotalFunctionEgressTrafficWithCostSerializer, + ResultTotalImagesWithCostSerializer, + ResultTotalInferenceWithCostSerializer, + ResultTotalInstanceWithCostSerializer, + ResultTotalLoadBalancerWithCostSerializer, + ResultTotalLogIndexWithCostSerializer, + ResultTotalSnapshotWithCostSerializer, + ResultTotalVolumeWithCostSerializer, + ResultTotalDbaasPostgreSQLPoolerWithCostSerializer, + ResultTotalDbaasPostgreSQLMemoryWithCostSerializer, + ResultTotalDbaasPostgreSQLPublicNetworkWithCostSerializer, + ResultTotalDbaasPostgreSqlcpuWithCostSerializer, + ResultTotalDbaasPostgreSQLVolumeWithCostSerializer, + ], + PropertyInfo(discriminator="type"), +] + + +class CostReportAggregatedMonthly(BaseModel): + count: int + """Total count of the totals""" + + price_status: Literal["error", "hide", "show"] + """Price status for the UI, type: string""" + + results: List[Result] diff --git a/src/gcore/types/cloud/cost_report_detailed.py b/src/gcore/types/cloud/cost_report_detailed.py new file mode 100644 index 00000000..348099af --- /dev/null +++ b/src/gcore/types/cloud/cost_report_detailed.py @@ -0,0 +1,1343 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "CostReportDetailed", + "Result", + "ResultResourceAIClusterWithCostSerializer", + "ResultResourceAIVirtualClusterWithCostSerializer", + "ResultResourceBaremetalWithCostSerializer", + "ResultResourceBasicVmWithCostSerializer", + "ResultResourceBackupWithCostSerializer", + "ResultResourceContainerWithCostSerializer", + "ResultResourceEgressTrafficWithCostSerializer", + "ResultResourceExternalIPWithCostSerializer", + "ResultResourceFileShareWithCostSerializer", + "ResultResourceFloatingIPWithCostSerializer", + "ResultResourceFunctionsWithCostSerializer", + "ResultResourceFunctionCallsWithCostSerializer", + "ResultResourceFunctionEgressTrafficWithCostSerializer", + "ResultResourceImagesWithCostSerializer", + "ResultResourceInferenceWithCostSerializer", + "ResultResourceInstanceWithCostSerializer", + "ResultResourceLoadBalancerWithCostSerializer", + "ResultResourceLogIndexWithCostSerializer", + "ResultResourceSnapshotWithCostSerializer", + "ResultResourceVolumeWithCostSerializer", + "ResultResourceDbaasPostgreSQLPoolerWithCostSerializer", + "ResultResourceDbaasPostgreSQLMemoryWithCostSerializer", + "ResultResourceDbaasPostgreSQLPublicNetworkWithCostSerializer", + "ResultResourceDbaasPostgreSqlcpuWithCostSerializer", + "ResultResourceDbaasPostgreSQLVolumeWithCostSerializer", +] + + +class ResultResourceAIClusterWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the Baremetal GPU cluster""" + + last_name: str + """Name of the AI cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["ai_cluster"] + + uuid: str + """UUID of the Baremetal GPU cluster""" + + +class ResultResourceAIVirtualClusterWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the Virtual GPU cluster""" + + last_name: str + """Name of the AI cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["ai_virtual_cluster"] + + uuid: str + """UUID of the Virtual GPU cluster""" + + +class ResultResourceBaremetalWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the bare metal server""" + + last_name: str + """Name of the bare metal server""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["baremetal"] + + uuid: str + """UUID of the bare metal server""" + + +class ResultResourceBasicVmWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the basic VM""" + + last_name: str + """Name of the basic VM""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["basic_vm"] + + uuid: str + """UUID of the basic VM""" + + +class ResultResourceBackupWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the backup""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + last_size: int + """Size of the backup in bytes""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + schedule_id: str + """ID of the backup schedule""" + + source_volume_uuid: str + """UUID of the source volume""" + + type: Literal["backup"] + + uuid: str + """UUID of the backup""" + + +class ResultResourceContainerWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GBS"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the container""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["containers"] + + uuid: str + """UUID of the container""" + + +class ResultResourceEgressTrafficWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["bytes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + instance_name: Optional[str] = None + """Name of the instance""" + + instance_type: Literal["baremetal", "vm"] + """Type of the instance""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + port_id: str + """ID of the port the traffic is associated with""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: str + """Unit of size""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["egress_traffic"] + + vm_id: str + """ID of the bare metal server the traffic is associated with""" + + +class ResultResourceExternalIPWithCostSerializer(BaseModel): + attached_to_vm: Optional[str] = None + """ID of the VM the IP is attached to""" + + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + ip_address: str + """IP address""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + network_id: str + """ID of the network the IP is attached to""" + + port_id: str + """ID of the port the IP is associated with""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + subnet_id: str + """ID of the subnet the IP is attached to""" + + type: Literal["external_ip"] + + +class ResultResourceFileShareWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + file_share_type: str + """Type of the file share""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the file share""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + last_size: int + """Size of the file share in bytes""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: Literal["GiB"] + """Unit of size""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["file_share"] + + uuid: str + """UUID of the file share""" + + +class ResultResourceFloatingIPWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + ip_address: str + """IP address""" + + last_name: str + """Name of the floating IP""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["floatingip"] + + uuid: str + """UUID of the floating IP""" + + +class ResultResourceFunctionsWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GBS"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the function""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions"] + + uuid: str + """UUID of the function""" + + +class ResultResourceFunctionCallsWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["MLS"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the function call""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions_calls"] + + uuid: str + """UUID of the function call""" + + +class ResultResourceFunctionEgressTrafficWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GB"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the function egress traffic""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions_traffic"] + + uuid: str + """UUID of the function egress traffic""" + + +class ResultResourceImagesWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the image""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + last_size: int + """Size of the image in bytes""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: Literal["bytes"] + """Unit of size""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["image"] + + uuid: str + """UUID of the image""" + + +class ResultResourceInferenceWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: str + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the inference deployment""" + + last_name: str + """Name of the inference deployment""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["inference"] + + uuid: str + """UUID of the inference deployment""" + + +class ResultResourceInstanceWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the instance""" + + last_name: str + """Name of the instance""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["instance"] + + uuid: str + """UUID of the instance""" + + +class ResultResourceLoadBalancerWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the load balancer""" + + last_name: str + """Name of the load balancer""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["load_balancer"] + + uuid: str + """UUID of the load balancer""" + + +class ResultResourceLogIndexWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the log index""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + last_size: int + """Size of the log index in bytes""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: str + """Unit of size""" + + type: Literal["log_index"] + + uuid: Optional[str] = None + """UUID of the log index""" + + +class ResultResourceSnapshotWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the snapshot""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + last_size: int + """Size of the snapshot in bytes""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: str + """Unit of size""" + + source_volume_uuid: str + """UUID of the source volume""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["snapshot"] + + uuid: str + """UUID of the snapshot""" + + volume_type: str + """Type of the volume""" + + +class ResultResourceVolumeWithCostSerializer(BaseModel): + attached_to_vm: Optional[str] = None + """ID of the VM the volume is attached to""" + + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the volume""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + last_size: int + """Size of the volume in bytes""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: str + """Unit of size""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["volume"] + + uuid: str + """UUID of the volume""" + + volume_type: str + """Type of the volume""" + + +class ResultResourceDbaasPostgreSQLPoolerWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_connection_pooler"] + + uuid: str + """UUID of the cluster""" + + +class ResultResourceDbaasPostgreSQLMemoryWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_memory"] + + uuid: str + """UUID of the cluster""" + + +class ResultResourceDbaasPostgreSQLPublicNetworkWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_public_network"] + + uuid: str + """UUID of the cluster""" + + +class ResultResourceDbaasPostgreSqlcpuWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_cpu"] + + uuid: str + """UUID of the cluster""" + + +class ResultResourceDbaasPostgreSQLVolumeWithCostSerializer(BaseModel): + billing_feature_name: Optional[str] = None + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + cost: Optional[float] = None + """Cost for requested period""" + + currency: Optional[str] = None + """Currency of the cost""" + + err: Optional[str] = None + """Error message""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: str + """Unit of size""" + + type: Literal["dbaas_postgresql_volume"] + + uuid: str + """UUID of the cluster""" + + volume_type: str + """Type of the volume""" + + +Result: TypeAlias = Annotated[ + Union[ + ResultResourceAIClusterWithCostSerializer, + ResultResourceAIVirtualClusterWithCostSerializer, + ResultResourceBaremetalWithCostSerializer, + ResultResourceBasicVmWithCostSerializer, + ResultResourceBackupWithCostSerializer, + ResultResourceContainerWithCostSerializer, + ResultResourceEgressTrafficWithCostSerializer, + ResultResourceExternalIPWithCostSerializer, + ResultResourceFileShareWithCostSerializer, + ResultResourceFloatingIPWithCostSerializer, + ResultResourceFunctionsWithCostSerializer, + ResultResourceFunctionCallsWithCostSerializer, + ResultResourceFunctionEgressTrafficWithCostSerializer, + ResultResourceImagesWithCostSerializer, + ResultResourceInferenceWithCostSerializer, + ResultResourceInstanceWithCostSerializer, + ResultResourceLoadBalancerWithCostSerializer, + ResultResourceLogIndexWithCostSerializer, + ResultResourceSnapshotWithCostSerializer, + ResultResourceVolumeWithCostSerializer, + ResultResourceDbaasPostgreSQLPoolerWithCostSerializer, + ResultResourceDbaasPostgreSQLMemoryWithCostSerializer, + ResultResourceDbaasPostgreSQLPublicNetworkWithCostSerializer, + ResultResourceDbaasPostgreSqlcpuWithCostSerializer, + ResultResourceDbaasPostgreSQLVolumeWithCostSerializer, + ], + PropertyInfo(discriminator="type"), +] + + +class CostReportDetailed(BaseModel): + count: int + """Count of all the resources""" + + price_status: Literal["error", "hide", "show"] + """Price status for the UI, type: string""" + + results: List[Result] diff --git a/src/gcore/types/cloud/cost_report_get_aggregated_monthly_params.py b/src/gcore/types/cloud/cost_report_get_aggregated_monthly_params.py new file mode 100644 index 00000000..133a3cc6 --- /dev/null +++ b/src/gcore/types/cloud/cost_report_get_aggregated_monthly_params.py @@ -0,0 +1,403 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = [ + "CostReportGetAggregatedMonthlyParams", + "SchemaFilter", + "SchemaFilterSchemaFilterSnapshotSerializer", + "SchemaFilterSchemaFilterInstanceSerializer", + "SchemaFilterSchemaFilterAIClusterSerializer", + "SchemaFilterSchemaFilterAIVirtualClusterSerializer", + "SchemaFilterSchemaFilterBasicVmSerializer", + "SchemaFilterSchemaFilterBaremetalSerializer", + "SchemaFilterSchemaFilterVolumeSerializer", + "SchemaFilterSchemaFilterFileShareSerializer", + "SchemaFilterSchemaFilterImageSerializer", + "SchemaFilterSchemaFilterFloatingIPSerializer", + "SchemaFilterSchemaFilterEgressTrafficSerializer", + "SchemaFilterSchemaFilterLoadBalancerSerializer", + "SchemaFilterSchemaFilterExternalIPSerializer", + "SchemaFilterSchemaFilterBackupSerializer", + "SchemaFilterSchemaFilterLogIndexSerializer", + "SchemaFilterSchemaFilterFunctionsSerializer", + "SchemaFilterSchemaFilterFunctionsCallsSerializer", + "SchemaFilterSchemaFilterFunctionsTrafficSerializer", + "SchemaFilterSchemaFilterContainersSerializer", + "SchemaFilterSchemaFilterInferenceSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer", + "Tags", + "TagsCondition", +] + + +class CostReportGetAggregatedMonthlyParams(TypedDict, total=False): + regions: Iterable[int] + """List of region IDs.""" + + response_format: Literal["csv_totals", "json"] + """Format of the response (`csv_totals` or json).""" + + rounding: bool + """Round cost values to 5 decimal places. When false, returns full precision.""" + + schema_filter: SchemaFilter + """Extended filter for field filtering.""" + + tags: Tags + """Filter by tags""" + + time_from: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """Deprecated. Use `year_month` instead. Beginning of the period: YYYY-mm""" + + time_to: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """Deprecated. Use `year_month` instead. End of the period: YYYY-mm""" + + types: List[ + Literal[ + "ai_cluster", + "ai_virtual_cluster", + "backup", + "baremetal", + "basic_vm", + "containers", + "dbaas_postgresql_connection_pooler", + "dbaas_postgresql_cpu", + "dbaas_postgresql_memory", + "dbaas_postgresql_public_network", + "dbaas_postgresql_volume", + "egress_traffic", + "external_ip", + "file_share", + "floatingip", + "functions", + "functions_calls", + "functions_traffic", + "image", + "inference", + "instance", + "load_balancer", + "log_index", + "snapshot", + "volume", + ] + ] + """List of resource types to be filtered in the report.""" + + year_month: str + """Year and month in the format YYYY-MM""" + + +class SchemaFilterSchemaFilterSnapshotSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "source_volume_uuid", "type", "uuid", "volume_type"]] + """Field name to filter by""" + + type: Required[Literal["snapshot"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterInstanceSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["instance"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterAIClusterSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["ai_cluster"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterAIVirtualClusterSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["ai_virtual_cluster"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterBasicVmSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["basic_vm"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterBaremetalSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["baremetal"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterVolumeSerializer(TypedDict, total=False): + field: Required[Literal["attached_to_vm", "last_name", "last_size", "type", "uuid", "volume_type"]] + """Field name to filter by""" + + type: Required[Literal["volume"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFileShareSerializer(TypedDict, total=False): + field: Required[Literal["file_share_type", "last_name", "last_size", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["file_share"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterImageSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["image"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFloatingIPSerializer(TypedDict, total=False): + field: Required[Literal["ip_address", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["floatingip"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterEgressTrafficSerializer(TypedDict, total=False): + field: Required[Literal["instance_name", "instance_type", "port_id", "type", "vm_id"]] + """Field name to filter by""" + + type: Required[Literal["egress_traffic"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterLoadBalancerSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["load_balancer"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterExternalIPSerializer(TypedDict, total=False): + field: Required[Literal["attached_to_vm", "ip_address", "network_id", "port_id", "subnet_id", "type"]] + """Field name to filter by""" + + type: Required[Literal["external_ip"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterBackupSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "schedule_id", "source_volume_uuid", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["backup"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterLogIndexSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["log_index"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFunctionsSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["functions"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFunctionsCallsSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["functions_calls"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFunctionsTrafficSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["functions_traffic"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterContainersSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["containers"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterInferenceSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["inference"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid", "volume_type"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_volume"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_public_network"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_cpu"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_memory"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_connection_pooler"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +SchemaFilter: TypeAlias = Union[ + SchemaFilterSchemaFilterSnapshotSerializer, + SchemaFilterSchemaFilterInstanceSerializer, + SchemaFilterSchemaFilterAIClusterSerializer, + SchemaFilterSchemaFilterAIVirtualClusterSerializer, + SchemaFilterSchemaFilterBasicVmSerializer, + SchemaFilterSchemaFilterBaremetalSerializer, + SchemaFilterSchemaFilterVolumeSerializer, + SchemaFilterSchemaFilterFileShareSerializer, + SchemaFilterSchemaFilterImageSerializer, + SchemaFilterSchemaFilterFloatingIPSerializer, + SchemaFilterSchemaFilterEgressTrafficSerializer, + SchemaFilterSchemaFilterLoadBalancerSerializer, + SchemaFilterSchemaFilterExternalIPSerializer, + SchemaFilterSchemaFilterBackupSerializer, + SchemaFilterSchemaFilterLogIndexSerializer, + SchemaFilterSchemaFilterFunctionsSerializer, + SchemaFilterSchemaFilterFunctionsCallsSerializer, + SchemaFilterSchemaFilterFunctionsTrafficSerializer, + SchemaFilterSchemaFilterContainersSerializer, + SchemaFilterSchemaFilterInferenceSerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer, + SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer, +] + + +class TagsCondition(TypedDict, total=False): + key: str + """The name of the tag to filter (e.g., 'os_version').""" + + strict: bool + """Determines how strictly the tag value must match the specified value. + + If true, the tag value must exactly match the given value. If false, a less + strict match (e.g., partial or case-insensitive match) may be applied. + """ + + value: str + """The value of the tag to filter (e.g., '22.04').""" + + +class Tags(TypedDict, total=False): + """Filter by tags""" + + conditions: Required[Iterable[TagsCondition]] + """A list of tag filtering conditions defining how tags should match.""" + + condition_type: Literal["AND", "OR"] + """Specifies whether conditions are combined using OR (default) or AND logic.""" diff --git a/src/gcore/types/cloud/cost_report_get_aggregated_params.py b/src/gcore/types/cloud/cost_report_get_aggregated_params.py new file mode 100644 index 00000000..df4c1727 --- /dev/null +++ b/src/gcore/types/cloud/cost_report_get_aggregated_params.py @@ -0,0 +1,415 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = [ + "CostReportGetAggregatedParams", + "SchemaFilter", + "SchemaFilterSchemaFilterSnapshotSerializer", + "SchemaFilterSchemaFilterInstanceSerializer", + "SchemaFilterSchemaFilterAIClusterSerializer", + "SchemaFilterSchemaFilterAIVirtualClusterSerializer", + "SchemaFilterSchemaFilterBasicVmSerializer", + "SchemaFilterSchemaFilterBaremetalSerializer", + "SchemaFilterSchemaFilterVolumeSerializer", + "SchemaFilterSchemaFilterFileShareSerializer", + "SchemaFilterSchemaFilterImageSerializer", + "SchemaFilterSchemaFilterFloatingIPSerializer", + "SchemaFilterSchemaFilterEgressTrafficSerializer", + "SchemaFilterSchemaFilterLoadBalancerSerializer", + "SchemaFilterSchemaFilterExternalIPSerializer", + "SchemaFilterSchemaFilterBackupSerializer", + "SchemaFilterSchemaFilterLogIndexSerializer", + "SchemaFilterSchemaFilterFunctionsSerializer", + "SchemaFilterSchemaFilterFunctionsCallsSerializer", + "SchemaFilterSchemaFilterFunctionsTrafficSerializer", + "SchemaFilterSchemaFilterContainersSerializer", + "SchemaFilterSchemaFilterInferenceSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer", + "Tags", + "TagsCondition", +] + + +class CostReportGetAggregatedParams(TypedDict, total=False): + time_from: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """The start date of the report period (ISO 8601). + + The report starts from the beginning of this day in UTC. + """ + + time_to: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """The end date of the report period (ISO 8601). + + The report ends just before the beginning of this day in UTC. + """ + + enable_last_day: bool + """Expenses for the last specified day are taken into account. + + As the default, False. + """ + + projects: Iterable[int] + """List of project IDs""" + + regions: Iterable[int] + """List of region IDs.""" + + response_format: Literal["csv_totals", "json"] + """Format of the response (csv or json).""" + + rounding: bool + """Round cost values to 5 decimal places. When false, returns full precision.""" + + schema_filter: SchemaFilter + """Extended filter for field filtering.""" + + tags: Tags + """Filter by tags""" + + types: List[ + Literal[ + "ai_cluster", + "ai_virtual_cluster", + "backup", + "baremetal", + "basic_vm", + "containers", + "dbaas_postgresql_connection_pooler", + "dbaas_postgresql_cpu", + "dbaas_postgresql_memory", + "dbaas_postgresql_public_network", + "dbaas_postgresql_volume", + "egress_traffic", + "external_ip", + "file_share", + "floatingip", + "functions", + "functions_calls", + "functions_traffic", + "image", + "inference", + "instance", + "load_balancer", + "log_index", + "snapshot", + "volume", + ] + ] + """List of resource types to be filtered in the report.""" + + +class SchemaFilterSchemaFilterSnapshotSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "source_volume_uuid", "type", "uuid", "volume_type"]] + """Field name to filter by""" + + type: Required[Literal["snapshot"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterInstanceSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["instance"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterAIClusterSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["ai_cluster"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterAIVirtualClusterSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["ai_virtual_cluster"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterBasicVmSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["basic_vm"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterBaremetalSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["baremetal"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterVolumeSerializer(TypedDict, total=False): + field: Required[Literal["attached_to_vm", "last_name", "last_size", "type", "uuid", "volume_type"]] + """Field name to filter by""" + + type: Required[Literal["volume"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFileShareSerializer(TypedDict, total=False): + field: Required[Literal["file_share_type", "last_name", "last_size", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["file_share"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterImageSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["image"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFloatingIPSerializer(TypedDict, total=False): + field: Required[Literal["ip_address", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["floatingip"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterEgressTrafficSerializer(TypedDict, total=False): + field: Required[Literal["instance_name", "instance_type", "port_id", "type", "vm_id"]] + """Field name to filter by""" + + type: Required[Literal["egress_traffic"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterLoadBalancerSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["load_balancer"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterExternalIPSerializer(TypedDict, total=False): + field: Required[Literal["attached_to_vm", "ip_address", "network_id", "port_id", "subnet_id", "type"]] + """Field name to filter by""" + + type: Required[Literal["external_ip"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterBackupSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "schedule_id", "source_volume_uuid", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["backup"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterLogIndexSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["log_index"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFunctionsSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["functions"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFunctionsCallsSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["functions_calls"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFunctionsTrafficSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["functions_traffic"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterContainersSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["containers"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterInferenceSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["inference"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid", "volume_type"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_volume"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_public_network"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_cpu"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_memory"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_connection_pooler"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +SchemaFilter: TypeAlias = Union[ + SchemaFilterSchemaFilterSnapshotSerializer, + SchemaFilterSchemaFilterInstanceSerializer, + SchemaFilterSchemaFilterAIClusterSerializer, + SchemaFilterSchemaFilterAIVirtualClusterSerializer, + SchemaFilterSchemaFilterBasicVmSerializer, + SchemaFilterSchemaFilterBaremetalSerializer, + SchemaFilterSchemaFilterVolumeSerializer, + SchemaFilterSchemaFilterFileShareSerializer, + SchemaFilterSchemaFilterImageSerializer, + SchemaFilterSchemaFilterFloatingIPSerializer, + SchemaFilterSchemaFilterEgressTrafficSerializer, + SchemaFilterSchemaFilterLoadBalancerSerializer, + SchemaFilterSchemaFilterExternalIPSerializer, + SchemaFilterSchemaFilterBackupSerializer, + SchemaFilterSchemaFilterLogIndexSerializer, + SchemaFilterSchemaFilterFunctionsSerializer, + SchemaFilterSchemaFilterFunctionsCallsSerializer, + SchemaFilterSchemaFilterFunctionsTrafficSerializer, + SchemaFilterSchemaFilterContainersSerializer, + SchemaFilterSchemaFilterInferenceSerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer, + SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer, +] + + +class TagsCondition(TypedDict, total=False): + key: str + """The name of the tag to filter (e.g., 'os_version').""" + + strict: bool + """Determines how strictly the tag value must match the specified value. + + If true, the tag value must exactly match the given value. If false, a less + strict match (e.g., partial or case-insensitive match) may be applied. + """ + + value: str + """The value of the tag to filter (e.g., '22.04').""" + + +class Tags(TypedDict, total=False): + """Filter by tags""" + + conditions: Required[Iterable[TagsCondition]] + """A list of tag filtering conditions defining how tags should match.""" + + condition_type: Literal["AND", "OR"] + """Specifies whether conditions are combined using OR (default) or AND logic.""" diff --git a/src/gcore/types/cloud/cost_report_get_detailed_params.py b/src/gcore/types/cloud/cost_report_get_detailed_params.py new file mode 100644 index 00000000..86361cf0 --- /dev/null +++ b/src/gcore/types/cloud/cost_report_get_detailed_params.py @@ -0,0 +1,441 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = [ + "CostReportGetDetailedParams", + "SchemaFilter", + "SchemaFilterSchemaFilterSnapshotSerializer", + "SchemaFilterSchemaFilterInstanceSerializer", + "SchemaFilterSchemaFilterAIClusterSerializer", + "SchemaFilterSchemaFilterAIVirtualClusterSerializer", + "SchemaFilterSchemaFilterBasicVmSerializer", + "SchemaFilterSchemaFilterBaremetalSerializer", + "SchemaFilterSchemaFilterVolumeSerializer", + "SchemaFilterSchemaFilterFileShareSerializer", + "SchemaFilterSchemaFilterImageSerializer", + "SchemaFilterSchemaFilterFloatingIPSerializer", + "SchemaFilterSchemaFilterEgressTrafficSerializer", + "SchemaFilterSchemaFilterLoadBalancerSerializer", + "SchemaFilterSchemaFilterExternalIPSerializer", + "SchemaFilterSchemaFilterBackupSerializer", + "SchemaFilterSchemaFilterLogIndexSerializer", + "SchemaFilterSchemaFilterFunctionsSerializer", + "SchemaFilterSchemaFilterFunctionsCallsSerializer", + "SchemaFilterSchemaFilterFunctionsTrafficSerializer", + "SchemaFilterSchemaFilterContainersSerializer", + "SchemaFilterSchemaFilterInferenceSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer", + "Sorting", + "Tags", + "TagsCondition", +] + + +class CostReportGetDetailedParams(TypedDict, total=False): + time_from: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """The start date of the report period (ISO 8601). + + The report starts from the beginning of this day in UTC. + """ + + time_to: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """The end date of the report period (ISO 8601). + + The report ends just before the beginning of this day in UTC. + """ + + enable_last_day: bool + """Expenses for the last specified day are taken into account. + + As the default, False. + """ + + limit: int + """The response resources limit. Defaults to 10.""" + + offset: int + """The response resources offset.""" + + projects: Iterable[int] + """List of project IDs""" + + regions: Iterable[int] + """List of region IDs.""" + + response_format: Literal["csv_records", "json"] + """Format of the response (csv or json).""" + + rounding: bool + """Round cost values to 5 decimal places. When false, returns full precision.""" + + schema_filter: SchemaFilter + """Extended filter for field filtering.""" + + sorting: Iterable[Sorting] + """List of sorting filters (JSON objects) fields: project. directions: asc, desc.""" + + tags: Tags + """Filter by tags""" + + types: List[ + Literal[ + "ai_cluster", + "ai_virtual_cluster", + "backup", + "baremetal", + "basic_vm", + "containers", + "dbaas_postgresql_connection_pooler", + "dbaas_postgresql_cpu", + "dbaas_postgresql_memory", + "dbaas_postgresql_public_network", + "dbaas_postgresql_volume", + "egress_traffic", + "external_ip", + "file_share", + "floatingip", + "functions", + "functions_calls", + "functions_traffic", + "image", + "inference", + "instance", + "load_balancer", + "log_index", + "snapshot", + "volume", + ] + ] + """List of resource types to be filtered in the report.""" + + +class SchemaFilterSchemaFilterSnapshotSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "source_volume_uuid", "type", "uuid", "volume_type"]] + """Field name to filter by""" + + type: Required[Literal["snapshot"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterInstanceSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["instance"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterAIClusterSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["ai_cluster"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterAIVirtualClusterSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["ai_virtual_cluster"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterBasicVmSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["basic_vm"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterBaremetalSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["baremetal"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterVolumeSerializer(TypedDict, total=False): + field: Required[Literal["attached_to_vm", "last_name", "last_size", "type", "uuid", "volume_type"]] + """Field name to filter by""" + + type: Required[Literal["volume"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFileShareSerializer(TypedDict, total=False): + field: Required[Literal["file_share_type", "last_name", "last_size", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["file_share"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterImageSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["image"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFloatingIPSerializer(TypedDict, total=False): + field: Required[Literal["ip_address", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["floatingip"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterEgressTrafficSerializer(TypedDict, total=False): + field: Required[Literal["instance_name", "instance_type", "port_id", "type", "vm_id"]] + """Field name to filter by""" + + type: Required[Literal["egress_traffic"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterLoadBalancerSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["load_balancer"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterExternalIPSerializer(TypedDict, total=False): + field: Required[Literal["attached_to_vm", "ip_address", "network_id", "port_id", "subnet_id", "type"]] + """Field name to filter by""" + + type: Required[Literal["external_ip"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterBackupSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "schedule_id", "source_volume_uuid", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["backup"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterLogIndexSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["log_index"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFunctionsSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["functions"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFunctionsCallsSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["functions_calls"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFunctionsTrafficSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["functions_traffic"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterContainersSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["containers"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterInferenceSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["inference"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid", "volume_type"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_volume"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_public_network"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_cpu"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_memory"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_connection_pooler"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +SchemaFilter: TypeAlias = Union[ + SchemaFilterSchemaFilterSnapshotSerializer, + SchemaFilterSchemaFilterInstanceSerializer, + SchemaFilterSchemaFilterAIClusterSerializer, + SchemaFilterSchemaFilterAIVirtualClusterSerializer, + SchemaFilterSchemaFilterBasicVmSerializer, + SchemaFilterSchemaFilterBaremetalSerializer, + SchemaFilterSchemaFilterVolumeSerializer, + SchemaFilterSchemaFilterFileShareSerializer, + SchemaFilterSchemaFilterImageSerializer, + SchemaFilterSchemaFilterFloatingIPSerializer, + SchemaFilterSchemaFilterEgressTrafficSerializer, + SchemaFilterSchemaFilterLoadBalancerSerializer, + SchemaFilterSchemaFilterExternalIPSerializer, + SchemaFilterSchemaFilterBackupSerializer, + SchemaFilterSchemaFilterLogIndexSerializer, + SchemaFilterSchemaFilterFunctionsSerializer, + SchemaFilterSchemaFilterFunctionsCallsSerializer, + SchemaFilterSchemaFilterFunctionsTrafficSerializer, + SchemaFilterSchemaFilterContainersSerializer, + SchemaFilterSchemaFilterInferenceSerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer, + SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer, +] + + +class Sorting(TypedDict, total=False): + billing_value: Literal["asc", "desc"] + + first_seen: Literal["asc", "desc"] + + last_name: Literal["asc", "desc"] + + last_seen: Literal["asc", "desc"] + + project: Literal["asc", "desc"] + + region: Literal["asc", "desc"] + + type: Literal["asc", "desc"] + + +class TagsCondition(TypedDict, total=False): + key: str + """The name of the tag to filter (e.g., 'os_version').""" + + strict: bool + """Determines how strictly the tag value must match the specified value. + + If true, the tag value must exactly match the given value. If false, a less + strict match (e.g., partial or case-insensitive match) may be applied. + """ + + value: str + """The value of the tag to filter (e.g., '22.04').""" + + +class Tags(TypedDict, total=False): + """Filter by tags""" + + conditions: Required[Iterable[TagsCondition]] + """A list of tag filtering conditions defining how tags should match.""" + + condition_type: Literal["AND", "OR"] + """Specifies whether conditions are combined using OR (default) or AND logic.""" diff --git a/src/gcore/types/cloud/databases/__init__.py b/src/gcore/types/cloud/databases/__init__.py new file mode 100644 index 00000000..f8ee8b14 --- /dev/null +++ b/src/gcore/types/cloud/databases/__init__.py @@ -0,0 +1,3 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations diff --git a/src/gcore/types/cloud/databases/postgres/__init__.py b/src/gcore/types/cloud/databases/postgres/__init__.py new file mode 100644 index 00000000..e4449e2b --- /dev/null +++ b/src/gcore/types/cloud/databases/postgres/__init__.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .postgres_cluster import PostgresCluster as PostgresCluster +from .pg_conf_validation import PgConfValidation as PgConfValidation +from .cluster_list_params import ClusterListParams as ClusterListParams +from .cluster_create_params import ClusterCreateParams as ClusterCreateParams +from .cluster_update_params import ClusterUpdateParams as ClusterUpdateParams +from .postgres_cluster_short import PostgresClusterShort as PostgresClusterShort +from .postgres_configuration import PostgresConfiguration as PostgresConfiguration +from .custom_configuration_validate_params import CustomConfigurationValidateParams as CustomConfigurationValidateParams diff --git a/src/gcore/types/cloud/databases/postgres/cluster_create_params.py b/src/gcore/types/cloud/databases/postgres/cluster_create_params.py new file mode 100644 index 00000000..f5a9e105 --- /dev/null +++ b/src/gcore/types/cloud/databases/postgres/cluster_create_params.py @@ -0,0 +1,116 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = [ + "ClusterCreateParams", + "Flavor", + "HighAvailability", + "Network", + "PgServerConfiguration", + "PgServerConfigurationPooler", + "Storage", + "Database", + "User", +] + + +class ClusterCreateParams(TypedDict, total=False): + project_id: int + + region_id: int + + cluster_name: Required[str] + """PostgreSQL cluster name""" + + flavor: Required[Flavor] + """Instance RAM and CPU""" + + high_availability: Required[Optional[HighAvailability]] + """High Availability settings""" + + network: Required[Network] + + pg_server_configuration: Required[PgServerConfiguration] + """PosgtreSQL cluster configuration""" + + storage: Required[Storage] + """Cluster's storage configuration""" + + databases: Iterable[Database] + + users: Iterable[User] + + +class Flavor(TypedDict, total=False): + """Instance RAM and CPU""" + + cpu: Required[int] + """Maximum available cores for instance""" + + memory_gib: Required[int] + """Maximum available RAM for instance""" + + +class HighAvailability(TypedDict, total=False): + """High Availability settings""" + + replication_mode: Required[Literal["async", "sync"]] + """Type of replication""" + + +class Network(TypedDict, total=False): + acl: Required[SequenceNotStr[str]] + """Allowed IPs and subnets for incoming traffic""" + + network_type: Required[Literal["public"]] + """Network Type""" + + +class PgServerConfigurationPooler(TypedDict, total=False): + mode: Required[Literal["session", "statement", "transaction"]] + + type: Literal["pgbouncer"] + + +class PgServerConfiguration(TypedDict, total=False): + """PosgtreSQL cluster configuration""" + + pg_conf: Required[str] + """pg.conf settings""" + + version: Required[str] + """Cluster version""" + + pooler: Optional[PgServerConfigurationPooler] + + +class Storage(TypedDict, total=False): + """Cluster's storage configuration""" + + size_gib: Required[int] + """Total available storage for database""" + + type: Required[str] + """Storage type""" + + +class Database(TypedDict, total=False): + name: Required[str] + """Database name""" + + owner: Required[str] + """Database owner from users list""" + + +class User(TypedDict, total=False): + name: Required[str] + """User name""" + + role_attributes: Required[List[Literal["BYPASSRLS", "CREATEDB", "CREATEROLE", "INHERIT", "LOGIN", "NOLOGIN"]]] + """User's attributes""" diff --git a/src/gcore/types/cloud/databases/postgres/cluster_list_params.py b/src/gcore/types/cloud/databases/postgres/cluster_list_params.py new file mode 100644 index 00000000..301f22e4 --- /dev/null +++ b/src/gcore/types/cloud/databases/postgres/cluster_list_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ClusterListParams"] + + +class ClusterListParams(TypedDict, total=False): + project_id: int + + region_id: int + + limit: int + """Maximum number of clusters to return""" + + offset: int + """Number of clusters to skip""" diff --git a/src/gcore/types/cloud/databases/postgres/cluster_update_params.py b/src/gcore/types/cloud/databases/postgres/cluster_update_params.py new file mode 100644 index 00000000..9ae130ff --- /dev/null +++ b/src/gcore/types/cloud/databases/postgres/cluster_update_params.py @@ -0,0 +1,110 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = [ + "ClusterUpdateParams", + "Database", + "Flavor", + "HighAvailability", + "Network", + "PgServerConfiguration", + "PgServerConfigurationPooler", + "Storage", + "User", +] + + +class ClusterUpdateParams(TypedDict, total=False): + project_id: int + + region_id: int + + databases: Iterable[Database] + + flavor: Optional[Flavor] + """New instance RAM and CPU""" + + high_availability: Optional[HighAvailability] + """New High Availability settings""" + + network: Optional[Network] + + pg_server_configuration: Optional[PgServerConfiguration] + """New PosgtreSQL cluster configuration""" + + storage: Optional[Storage] + """New storage configuration""" + + users: Iterable[User] + + +class Database(TypedDict, total=False): + name: Required[str] + """Database name""" + + owner: Required[str] + """Database owner from users list""" + + +class Flavor(TypedDict, total=False): + """New instance RAM and CPU""" + + cpu: Required[int] + """Maximum available cores for instance""" + + memory_gib: Required[int] + """Maximum available RAM for instance""" + + +class HighAvailability(TypedDict, total=False): + """New High Availability settings""" + + replication_mode: Required[Literal["async", "sync"]] + """Type of replication""" + + +class Network(TypedDict, total=False): + acl: Required[SequenceNotStr[str]] + """Allowed IPs and subnets for incoming traffic""" + + network_type: Required[Literal["public"]] + """Network Type""" + + +class PgServerConfigurationPooler(TypedDict, total=False): + mode: Required[Literal["session", "statement", "transaction"]] + + type: Literal["pgbouncer"] + + +class PgServerConfiguration(TypedDict, total=False): + """New PosgtreSQL cluster configuration""" + + pg_conf: Optional[str] + """New pg.conf file settings""" + + pooler: Optional[PgServerConfigurationPooler] + + version: Optional[str] + """New cluster version""" + + +class Storage(TypedDict, total=False): + """New storage configuration""" + + size_gib: Required[int] + """Total available storage for database""" + + +class User(TypedDict, total=False): + name: Required[str] + """User name""" + + role_attributes: Required[List[Literal["BYPASSRLS", "CREATEDB", "CREATEROLE", "INHERIT", "LOGIN", "NOLOGIN"]]] + """User's attributes""" diff --git a/src/gcore/types/cloud/databases/postgres/clusters/__init__.py b/src/gcore/types/cloud/databases/postgres/clusters/__init__.py new file mode 100644 index 00000000..254c35c0 --- /dev/null +++ b/src/gcore/types/cloud/databases/postgres/clusters/__init__.py @@ -0,0 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .postgres_user_credentials import PostgresUserCredentials as PostgresUserCredentials diff --git a/src/gcore/types/cloud/databases/postgres/clusters/postgres_user_credentials.py b/src/gcore/types/cloud/databases/postgres/clusters/postgres_user_credentials.py new file mode 100644 index 00000000..fd38e6c6 --- /dev/null +++ b/src/gcore/types/cloud/databases/postgres/clusters/postgres_user_credentials.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ......_models import BaseModel + +__all__ = ["PostgresUserCredentials"] + + +class PostgresUserCredentials(BaseModel): + password: str + """Password""" + + username: str + """Username""" diff --git a/src/gcore/types/cloud/databases/postgres/custom_configuration_validate_params.py b/src/gcore/types/cloud/databases/postgres/custom_configuration_validate_params.py new file mode 100644 index 00000000..2cd791ae --- /dev/null +++ b/src/gcore/types/cloud/databases/postgres/custom_configuration_validate_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["CustomConfigurationValidateParams"] + + +class CustomConfigurationValidateParams(TypedDict, total=False): + project_id: int + + region_id: int + + pg_conf: Required[str] + """PostgreSQL configuration""" + + version: Required[str] + """PostgreSQL version""" diff --git a/src/gcore/types/cloud/databases/postgres/pg_conf_validation.py b/src/gcore/types/cloud/databases/postgres/pg_conf_validation.py new file mode 100644 index 00000000..8e4ae232 --- /dev/null +++ b/src/gcore/types/cloud/databases/postgres/pg_conf_validation.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ....._models import BaseModel + +__all__ = ["PgConfValidation"] + + +class PgConfValidation(BaseModel): + errors: List[str] + """Errors list""" + + is_valid: bool + """Validity of pg.conf file""" diff --git a/src/gcore/types/cloud/databases/postgres/postgres_cluster.py b/src/gcore/types/cloud/databases/postgres/postgres_cluster.py new file mode 100644 index 00000000..a5abc748 --- /dev/null +++ b/src/gcore/types/cloud/databases/postgres/postgres_cluster.py @@ -0,0 +1,124 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = [ + "PostgresCluster", + "Database", + "Flavor", + "HighAvailability", + "Network", + "PgServerConfiguration", + "PgServerConfigurationPooler", + "Storage", + "User", +] + + +class Database(BaseModel): + name: str + """Database name""" + + owner: str + """Database owner from users list""" + + size: int + """Size in bytes""" + + +class Flavor(BaseModel): + """Instance RAM and CPU""" + + cpu: int + """Maximum available cores for instance""" + + memory_gib: int + """Maximum available RAM for instance""" + + +class HighAvailability(BaseModel): + replication_mode: Literal["async", "sync"] + """Type of replication""" + + +class Network(BaseModel): + acl: List[str] + """Allowed IPs and subnets for incoming traffic""" + + connection_string: str + """Connection string to main database""" + + host: str + """database hostname""" + + network_type: Literal["public"] + """Network Type""" + + +class PgServerConfigurationPooler(BaseModel): + mode: Literal["session", "statement", "transaction"] + + type: Optional[Literal["pgbouncer"]] = None + + +class PgServerConfiguration(BaseModel): + """Main PG configuration""" + + pg_conf: str + """pg.conf settings""" + + version: str + """Cluster version""" + + pooler: Optional[PgServerConfigurationPooler] = None + + +class Storage(BaseModel): + """PG's storage configuration""" + + size_gib: int + """Total available storage for database""" + + type: str + """Storage type""" + + +class User(BaseModel): + is_secret_revealed: bool + """Display was secret revealed or not""" + + name: str + """User name""" + + role_attributes: List[Literal["BYPASSRLS", "CREATEDB", "CREATEROLE", "INHERIT", "LOGIN", "NOLOGIN"]] + """User's attributes""" + + +class PostgresCluster(BaseModel): + cluster_name: str + + created_at: datetime + + databases: List[Database] + + flavor: Flavor + """Instance RAM and CPU""" + + high_availability: Optional[HighAvailability] = None + + network: Network + + pg_server_configuration: PgServerConfiguration + """Main PG configuration""" + + status: Literal["DELETING", "FAILED", "PREPARING", "READY", "UNHEALTHY", "UNKNOWN", "UPDATING"] + """Current cluster status""" + + storage: Storage + """PG's storage configuration""" + + users: List[User] diff --git a/src/gcore/types/cloud/databases/postgres/postgres_cluster_short.py b/src/gcore/types/cloud/databases/postgres/postgres_cluster_short.py new file mode 100644 index 00000000..1a197123 --- /dev/null +++ b/src/gcore/types/cloud/databases/postgres/postgres_cluster_short.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["PostgresClusterShort"] + + +class PostgresClusterShort(BaseModel): + cluster_name: str + """PostgreSQL cluster name""" + + created_at: datetime + """Creation timestamp""" + + status: Literal["DELETING", "FAILED", "PREPARING", "READY", "UNHEALTHY", "UNKNOWN", "UPDATING"] + """Current cluster status""" + + version: str + """Cluster version""" diff --git a/src/gcore/types/cloud/databases/postgres/postgres_configuration.py b/src/gcore/types/cloud/databases/postgres/postgres_configuration.py new file mode 100644 index 00000000..8be36800 --- /dev/null +++ b/src/gcore/types/cloud/databases/postgres/postgres_configuration.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ....._models import BaseModel + +__all__ = ["PostgresConfiguration", "Flavor", "StorageClass"] + + +class Flavor(BaseModel): + cpu: int + """Maximum available cores for instance""" + + memory_gib: int + """Maximum available RAM for instance""" + + pg_conf: str + + +class StorageClass(BaseModel): + name: str + """Storage type""" + + +class PostgresConfiguration(BaseModel): + flavors: List[Flavor] + + storage_classes: List[StorageClass] + + versions: List[str] + """Available versions""" diff --git a/src/gcore/types/cloud/ddos_profile.py b/src/gcore/types/cloud/ddos_profile.py new file mode 100644 index 00000000..2db25f56 --- /dev/null +++ b/src/gcore/types/cloud/ddos_profile.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .ddos_profile_field import DDOSProfileField +from .ddos_profile_status import DDOSProfileStatus +from .ddos_profile_template import DDOSProfileTemplate +from .ddos_profile_option_list import DDOSProfileOptionList + +__all__ = ["DDOSProfile", "Protocol"] + + +class Protocol(BaseModel): + port: str + """Network port number for which protocols are configured""" + + protocols: List[str] + """List of network protocols enabled on the specified port""" + + +class DDOSProfile(BaseModel): + id: int + """Unique identifier for the DDoS protection profile""" + + fields: List[DDOSProfileField] + """List of configured field values for the protection profile""" + + options: DDOSProfileOptionList + """Configuration options controlling profile activation and BGP routing""" + + profile_template: Optional[DDOSProfileTemplate] = None + """Complete template configuration data used for this profile""" + + profile_template_description: Optional[str] = None + """Detailed description of the protection template used for this profile""" + + protocols: Optional[List[Protocol]] = None + """List of network protocols and ports configured for protection""" + + site: Optional[str] = None + """Geographic site identifier where the protection is deployed""" + + status: Optional[DDOSProfileStatus] = None + """Current operational status and any error information for the profile""" diff --git a/src/gcore/types/cloud/ddos_profile_field.py b/src/gcore/types/cloud/ddos_profile_field.py new file mode 100644 index 00000000..0bcfbca1 --- /dev/null +++ b/src/gcore/types/cloud/ddos_profile_field.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["DDOSProfileField"] + + +class DDOSProfileField(BaseModel): + id: int + """Unique identifier for the DDoS protection field""" + + base_field: Optional[int] = None + """ID of DDoS profile field""" + + default: Optional[str] = None + """Predefined default value for the field if not specified""" + + description: Optional[str] = None + """Detailed description explaining the field's purpose and usage guidelines""" + + field_name: Optional[str] = None + """Name of DDoS profile field""" + + field_type: Optional[str] = None + """Data type classification of the field (e.g., string, integer, array)""" + + field_value: object + """Complex value. Only one of 'value' or 'field_value' must be specified.""" + + name: str + """Human-readable name of the protection field""" + + required: Optional[bool] = None + """ + Indicates whether this field must be provided when creating a protection profile + """ + + validation_schema: object + """JSON schema defining validation rules and constraints for the field value""" + + value: Optional[str] = None + """Basic type value. Only one of 'value' or 'field_value' must be specified.""" diff --git a/src/gcore/types/cloud/ddos_profile_option_list.py b/src/gcore/types/cloud/ddos_profile_option_list.py new file mode 100644 index 00000000..cd7729a0 --- /dev/null +++ b/src/gcore/types/cloud/ddos_profile_option_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["DDOSProfileOptionList"] + + +class DDOSProfileOptionList(BaseModel): + active: bool + """ + Controls whether the DDoS protection profile is enabled and actively protecting + the resource + """ + + bgp: bool + """Enables Border Gateway Protocol (BGP) routing for DDoS protection traffic""" diff --git a/src/gcore/types/cloud/ddos_profile_status.py b/src/gcore/types/cloud/ddos_profile_status.py new file mode 100644 index 00000000..d76982fd --- /dev/null +++ b/src/gcore/types/cloud/ddos_profile_status.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["DDOSProfileStatus"] + + +class DDOSProfileStatus(BaseModel): + error_description: str + """Detailed error message describing any issues with the profile operation""" + + status: str + """Current operational status of the DDoS protection profile""" diff --git a/src/gcore/types/cloud/ddos_profile_template.py b/src/gcore/types/cloud/ddos_profile_template.py new file mode 100644 index 00000000..5fcaa343 --- /dev/null +++ b/src/gcore/types/cloud/ddos_profile_template.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .ddos_profile_template_field import DDOSProfileTemplateField + +__all__ = ["DDOSProfileTemplate"] + + +class DDOSProfileTemplate(BaseModel): + id: int + """Unique identifier for the DDoS protection template""" + + description: Optional[str] = None + """Detailed description explaining the template's purpose and use cases""" + + fields: List[DDOSProfileTemplateField] + """List of configurable fields that define the template's protection parameters""" + + name: str + """Human-readable name of the protection template""" diff --git a/src/gcore/types/cloud/ddos_profile_template_field.py b/src/gcore/types/cloud/ddos_profile_template_field.py new file mode 100644 index 00000000..96256752 --- /dev/null +++ b/src/gcore/types/cloud/ddos_profile_template_field.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["DDOSProfileTemplateField"] + + +class DDOSProfileTemplateField(BaseModel): + id: int + """Unique identifier for the DDoS protection field""" + + default: Optional[str] = None + """Predefined default value for the field if not specified""" + + description: Optional[str] = None + """Detailed description explaining the field's purpose and usage guidelines""" + + field_type: Optional[str] = None + """Data type classification of the field (e.g., string, integer, array)""" + + name: str + """Human-readable name of the protection field""" + + required: Optional[bool] = None + """ + Indicates whether this field must be provided when creating a protection profile + """ + + validation_schema: object + """JSON schema defining validation rules and constraints for the field value""" diff --git a/src/gcore/types/cloud/file_share.py b/src/gcore/types/cloud/file_share.py new file mode 100644 index 00000000..a334740b --- /dev/null +++ b/src/gcore/types/cloud/file_share.py @@ -0,0 +1,152 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from .tag import Tag +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "FileShare", + "ShareSettings", + "ShareSettingsStandardShareSettingsOutputSerializer", + "ShareSettingsVastShareSettingsOutputSerializer", +] + + +class ShareSettingsStandardShareSettingsOutputSerializer(BaseModel): + type_name: Literal["standard"] + """Standard file share type""" + + +class ShareSettingsVastShareSettingsOutputSerializer(BaseModel): + allowed_characters: Optional[Literal["LCD", "NPL"]] = None + + path_length: Optional[Literal["LCD", "NPL"]] = None + + root_squash: bool + """Enables or disables root squash for NFS clients. + + - If `true`, root squash is enabled: the root user is mapped to nobody for all + file and folder management operations on the export. + - If `false`, root squash is disabled: the NFS client `root` user retains root + privileges. + """ + + type_name: Literal["vast"] + """Vast file share type""" + + +ShareSettings: TypeAlias = Annotated[ + Union[ShareSettingsStandardShareSettingsOutputSerializer, ShareSettingsVastShareSettingsOutputSerializer], + PropertyInfo(discriminator="type_name"), +] + + +class FileShare(BaseModel): + id: str + """File share ID""" + + connection_point: Optional[str] = None + """Connection point. Can be null during File share creation""" + + created_at: str + """Datetime when the file share was created""" + + creator_task_id: str + """Task that created this entity""" + + name: str + """File share name""" + + network_id: str + """Network ID.""" + + network_name: str + """Network name.""" + + project_id: int + """Project ID""" + + protocol: str + """File share protocol""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + share_network_name: Optional[str] = None + """Share network name. + + May be null if the file share was created with volume type VAST + """ + + share_settings: ShareSettings + """Share settings specific to the file share type""" + + size: int + """File share size in GiB""" + + status: Literal[ + "available", + "awaiting_transfer", + "backup_creating", + "backup_restoring", + "backup_restoring_error", + "creating", + "creating_from_snapshot", + "deleted", + "deleting", + "ensuring", + "error", + "error_deleting", + "extending", + "extending_error", + "inactive", + "manage_error", + "manage_starting", + "migrating", + "migrating_to", + "replication_change", + "reverting", + "reverting_error", + "shrinking", + "shrinking_error", + "shrinking_possible_data_loss_error", + "unmanage_error", + "unmanage_starting", + "unmanaged", + ] + """File share status""" + + subnet_id: str + """Subnet ID.""" + + subnet_name: str + """Subnet name.""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + type_name: Literal["standard", "vast"] + """File share type name""" + + volume_type: Literal["default_share_type", "vast_share_type"] + """Deprecated. Use `type_name` instead. File share disk type""" diff --git a/src/gcore/types/cloud/file_share_create_params.py b/src/gcore/types/cloud/file_share_create_params.py new file mode 100644 index 00000000..5dca72de --- /dev/null +++ b/src/gcore/types/cloud/file_share_create_params.py @@ -0,0 +1,148 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "FileShareCreateParams", + "CreateStandardFileShareSerializer", + "CreateStandardFileShareSerializerNetwork", + "CreateStandardFileShareSerializerAccess", + "CreateVastFileShareSerializer", + "CreateVastFileShareSerializerShareSettings", +] + + +class CreateStandardFileShareSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: Required[str] + """File share name""" + + network: Required[CreateStandardFileShareSerializerNetwork] + """File share network configuration""" + + protocol: Required[Literal["NFS"]] + """File share protocol""" + + size: Required[int] + """File share size in GiB""" + + access: Iterable[CreateStandardFileShareSerializerAccess] + """Access Rules""" + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + type_name: Literal["standard"] + """Standard file share type""" + + volume_type: Literal["default_share_type"] + """Deprecated. Use `type_name` instead.""" + + +class CreateStandardFileShareSerializerNetwork(TypedDict, total=False): + """File share network configuration""" + + network_id: Required[str] + """Network ID.""" + + subnet_id: str + """Subnetwork ID. + + If the subnet is not selected, it will be selected automatically. + """ + + +class CreateStandardFileShareSerializerAccess(TypedDict, total=False): + access_mode: Required[Literal["ro", "rw"]] + """Access mode""" + + ip_address: Required[str] + """Source IP or network""" + + +class CreateVastFileShareSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: Required[str] + """File share name""" + + protocol: Required[Literal["NFS"]] + """File share protocol""" + + size: Required[int] + """File share size in GiB""" + + share_settings: CreateVastFileShareSerializerShareSettings + """Configuration settings for the share""" + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + type_name: Literal["vast"] + """Vast file share type""" + + volume_type: Literal["vast_share_type"] + """Deprecated. Use `type_name` instead.""" + + +class CreateVastFileShareSerializerShareSettings(TypedDict, total=False): + """Configuration settings for the share""" + + allowed_characters: Literal["LCD", "NPL"] + """Determines which characters are allowed in file names. Choose between: + + - Lowest Common Denominator (LCD), allows only characters allowed by all VAST + Cluster-supported protocols + - Native Protocol Limit (NPL), imposes no limitation beyond that of the client + protocol. + """ + + path_length: Literal["LCD", "NPL"] + """Affects the maximum limit of file path component name length. Choose between: + + - Lowest Common Denominator (LCD), imposes the lowest common denominator file + length limit of all VAST Cluster-supported protocols. With this (default) + option, the limitation on the length of a single component of the path is 255 + characters + - Native Protocol Limit (NPL), imposes no limitation beyond that of the client + protocol. + """ + + root_squash: bool + """Enables or disables root squash for NFS clients. + + - If `true` (default), root squash is enabled: the root user is mapped to nobody + for all file and folder management operations on the export. + - If `false`, root squash is disabled: the NFS client `root` user retains root + privileges. Use this option if you trust the root user not to perform + operations that will corrupt data. + """ + + +FileShareCreateParams: TypeAlias = Union[CreateStandardFileShareSerializer, CreateVastFileShareSerializer] diff --git a/src/gcore/types/cloud/file_share_list_params.py b/src/gcore/types/cloud/file_share_list_params.py new file mode 100644 index 00000000..7f72417d --- /dev/null +++ b/src/gcore/types/cloud/file_share_list_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["FileShareListParams"] + + +class FileShareListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + limit: int + """Optional. Limit the number of returned items""" + + name: str + """File share name. Uses partial match.""" + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ + + type_name: Literal["standard", "vast"] + """File share type name""" diff --git a/src/gcore/types/cloud/file_share_resize_params.py b/src/gcore/types/cloud/file_share_resize_params.py new file mode 100644 index 00000000..8f135a4d --- /dev/null +++ b/src/gcore/types/cloud/file_share_resize_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["FileShareResizeParams"] + + +class FileShareResizeParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + size: Required[int] + """File Share new size in GiB.""" diff --git a/src/gcore/types/cloud/file_share_update_params.py b/src/gcore/types/cloud/file_share_update_params.py new file mode 100644 index 00000000..11745736 --- /dev/null +++ b/src/gcore/types/cloud/file_share_update_params.py @@ -0,0 +1,83 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +from .tag_update_map_param import TagUpdateMapParam + +__all__ = ["FileShareUpdateParams", "ShareSettings"] + + +class FileShareUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: str + """Name""" + + share_settings: ShareSettings + """Configuration settings for the share""" + + tags: Optional[TagUpdateMapParam] + """Update key-value tags using JSON Merge Patch semantics (RFC 7386). + + Provide key-value pairs to add or update tags. Set tag values to `null` to + remove tags. Unspecified tags remain unchanged. Read-only tags are always + preserved and cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + """ + + +class ShareSettings(TypedDict, total=False): + """Configuration settings for the share""" + + allowed_characters: Literal["LCD", "NPL"] + """Determines which characters are allowed in file names. Choose between: + + - Lowest Common Denominator (LCD), allows only characters allowed by all VAST + Cluster-supported protocols + - Native Protocol Limit (NPL), imposes no limitation beyond that of the client + protocol. + """ + + path_length: Literal["LCD", "NPL"] + """Affects the maximum limit of file path component name length. Choose between: + + - Lowest Common Denominator (LCD), imposes the lowest common denominator file + length limit of all VAST Cluster-supported protocols. With this (default) + option, the limitation on the length of a single component of the path is 255 + characters + - Native Protocol Limit (NPL), imposes no limitation beyond that of the client + protocol. + """ + + root_squash: bool + """Enables or disables root squash for NFS clients. + + - If `true` (default), root squash is enabled: the root user is mapped to nobody + for all file and folder management operations on the export. + - If `false`, root squash is disabled: the NFS client `root` user retains root + privileges. Use this option if you trust the root user not to perform + operations that will corrupt data. + """ diff --git a/src/gcore/types/cloud/file_shares/__init__.py b/src/gcore/types/cloud/file_shares/__init__.py new file mode 100644 index 00000000..59fee441 --- /dev/null +++ b/src/gcore/types/cloud/file_shares/__init__.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .access_rule import AccessRule as AccessRule +from .access_rule_list import AccessRuleList as AccessRuleList +from .access_rule_create_params import AccessRuleCreateParams as AccessRuleCreateParams diff --git a/src/gcore/types/cloud/file_shares/access_rule.py b/src/gcore/types/cloud/file_shares/access_rule.py new file mode 100644 index 00000000..49d04b63 --- /dev/null +++ b/src/gcore/types/cloud/file_shares/access_rule.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["AccessRule"] + + +class AccessRule(BaseModel): + id: str + """Access Rule ID""" + + access_level: Literal["ro", "rw"] + """Access mode""" + + access_to: str + """Source IP or network""" + + state: Literal["active", "applying", "denying", "error", "new", "queued_to_apply", "queued_to_deny"] + """Access Rule state""" diff --git a/src/gcore/types/cloud/file_shares/access_rule_create_params.py b/src/gcore/types/cloud/file_shares/access_rule_create_params.py new file mode 100644 index 00000000..6edc7b7d --- /dev/null +++ b/src/gcore/types/cloud/file_shares/access_rule_create_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AccessRuleCreateParams"] + + +class AccessRuleCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + access_mode: Required[Literal["ro", "rw"]] + """Access mode""" + + ip_address: Required[str] + """Source IP or network""" diff --git a/src/gcore/types/cloud/file_shares/access_rule_list.py b/src/gcore/types/cloud/file_shares/access_rule_list.py new file mode 100644 index 00000000..2951c96d --- /dev/null +++ b/src/gcore/types/cloud/file_shares/access_rule_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ...._models import BaseModel +from .access_rule import AccessRule + +__all__ = ["AccessRuleList"] + + +class AccessRuleList(BaseModel): + count: int + """Number of objects""" + + results: List[AccessRule] + """Objects""" diff --git a/src/gcore/types/cloud/fixed_address.py b/src/gcore/types/cloud/fixed_address.py new file mode 100644 index 00000000..4a4a1e06 --- /dev/null +++ b/src/gcore/types/cloud/fixed_address.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["FixedAddress"] + + +class FixedAddress(BaseModel): + """Schema for `fixed` addresses. + + This schema is used when fetching a single instance. + """ + + addr: str + """IP address""" + + interface_name: Optional[str] = None + """Interface name. + + This field will be `null` if `with_interfaces_name=true` is not set in the + request when listing instances. It will also be `null` if the `interface_name` + was not specified during instance creation or when attaching the interface. + """ + + subnet_id: str + """The unique identifier of the subnet associated with this address. + + Included only in the response for a single-resource lookup (GET by ID). For the + trunk subports, this field is always set. + """ + + subnet_name: str + """The name of the subnet associated with this address. + + Included only in the response for a single-resource lookup (GET by ID). For the + trunk subports, this field is always set. + """ + + type: Literal["fixed"] + """Type of the address""" diff --git a/src/gcore/types/cloud/fixed_address_short.py b/src/gcore/types/cloud/fixed_address_short.py new file mode 100644 index 00000000..58fbb4e6 --- /dev/null +++ b/src/gcore/types/cloud/fixed_address_short.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["FixedAddressShort"] + + +class FixedAddressShort(BaseModel): + """Schema for `fixed` addresses. + + This schema is used when listing instances. + It omits the `subnet_name` and `subnet_id` fields. + """ + + addr: str + """IP address""" + + interface_name: Optional[str] = None + """Interface name. + + This field will be `null` if `with_interfaces_name=true` is not set in the + request when listing instances. It will also be `null` if the `interface_name` + was not specified during instance creation or when attaching the interface. + """ + + type: Literal["fixed"] + """Type of the address""" diff --git a/src/gcore/types/cloud/floating_address.py b/src/gcore/types/cloud/floating_address.py new file mode 100644 index 00000000..80c4876c --- /dev/null +++ b/src/gcore/types/cloud/floating_address.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["FloatingAddress"] + + +class FloatingAddress(BaseModel): + """Schema for `floating` addresses.""" + + addr: str + """Address""" + + type: Literal["floating"] + """Type of the address""" diff --git a/src/gcore/types/cloud/floating_ip.py b/src/gcore/types/cloud/floating_ip.py new file mode 100644 index 00000000..6d7cb0d1 --- /dev/null +++ b/src/gcore/types/cloud/floating_ip.py @@ -0,0 +1,72 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from .tag import Tag +from ..._models import BaseModel +from .floating_ip_status import FloatingIPStatus + +__all__ = ["FloatingIP"] + + +class FloatingIP(BaseModel): + id: str + """Floating IP ID""" + + created_at: datetime + """Datetime when the floating IP was created""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + fixed_ip_address: Optional[str] = None + """IP address of the port the floating IP is attached to""" + + floating_ip_address: Optional[str] = None + """IP Address of the floating IP""" + + port_id: Optional[str] = None + """Port ID the floating IP is attached to. + + The `fixed_ip_address` is the IP address of the port. + """ + + project_id: int + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + router_id: Optional[str] = None + """Router ID""" + + status: Optional[FloatingIPStatus] = None + """Floating IP status. + + DOWN - unassigned (available). ACTIVE - attached to a port (in use). ERROR - + error state. + """ + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + updated_at: datetime + """Datetime when the floating IP was last updated""" diff --git a/src/gcore/types/cloud/floating_ip_assign_params.py b/src/gcore/types/cloud/floating_ip_assign_params.py new file mode 100644 index 00000000..6e3cf613 --- /dev/null +++ b/src/gcore/types/cloud/floating_ip_assign_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +__all__ = ["FloatingIPAssignParams"] + + +class FloatingIPAssignParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + port_id: Required[str] + """Port ID""" + + fixed_ip_address: Optional[str] + """Fixed IP address""" diff --git a/src/gcore/types/cloud/floating_ip_create_params.py b/src/gcore/types/cloud/floating_ip_create_params.py new file mode 100644 index 00000000..ee28a9e9 --- /dev/null +++ b/src/gcore/types/cloud/floating_ip_create_params.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +__all__ = ["FloatingIPCreateParams"] + + +class FloatingIPCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + fixed_ip_address: Optional[str] + """ + If the port has multiple IP addresses, a specific one can be selected using this + field. If not specified, the first IP in the port's list will be used by + default. + """ + + port_id: Optional[str] + """ + If provided, the floating IP will be immediately attached to the specified port. + """ + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ diff --git a/src/gcore/types/cloud/floating_ip_detailed.py b/src/gcore/types/cloud/floating_ip_detailed.py new file mode 100644 index 00000000..65d9bb30 --- /dev/null +++ b/src/gcore/types/cloud/floating_ip_detailed.py @@ -0,0 +1,221 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, TypeAlias + +from .tag import Tag +from ..._models import BaseModel +from .fixed_address import FixedAddress +from .load_balancer import LoadBalancer +from .floating_address import FloatingAddress +from .floating_ip_status import FloatingIPStatus +from .fixed_address_short import FixedAddressShort + +__all__ = [ + "FloatingIPDetailed", + "Instance", + "InstanceAddress", + "InstanceFlavor", + "InstanceSecurityGroup", + "InstanceVolume", +] + +InstanceAddress: TypeAlias = Union[FloatingAddress, FixedAddressShort, FixedAddress] + + +class InstanceFlavor(BaseModel): + """Flavor""" + + flavor_id: str + """Flavor ID is the same as name""" + + flavor_name: str + """Flavor name""" + + ram: int + """RAM size in MiB""" + + vcpus: int + """Virtual CPU count. For bare metal flavors, it's a physical CPU count""" + + +class InstanceSecurityGroup(BaseModel): + name: str + """Name.""" + + +class InstanceVolume(BaseModel): + id: str + """Volume ID""" + + delete_on_termination: bool + """Whether the volume is deleted together with the VM""" + + +class Instance(BaseModel): + """Instance the floating IP is attached to""" + + id: str + """Instance ID""" + + addresses: Dict[str, List[InstanceAddress]] + """Map of `network_name` to list of addresses in that network""" + + created_at: datetime + """Datetime when instance was created""" + + creator_task_id: str + """Task that created this entity""" + + flavor: InstanceFlavor + """Flavor""" + + instance_description: Optional[str] = None + """Instance description""" + + name: str + """Instance name""" + + project_id: int + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + security_groups: List[InstanceSecurityGroup] + """Security groups""" + + ssh_key_name: Optional[str] = None + """SSH key name assigned to instance""" + + status: Literal[ + "ACTIVE", + "BUILD", + "DELETED", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PASSWORD", + "PAUSED", + "REBOOT", + "REBUILD", + "RESCUE", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "UNKNOWN", + "VERIFY_RESIZE", + ] + """Instance status""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + task_state: Optional[str] = None + """Task state""" + + vm_state: Literal[ + "active", + "building", + "deleted", + "error", + "paused", + "rescued", + "resized", + "shelved", + "shelved_offloaded", + "soft-deleted", + "stopped", + "suspended", + ] + """Virtual machine state (active)""" + + volumes: List[InstanceVolume] + """List of volumes""" + + +class FloatingIPDetailed(BaseModel): + id: str + """Floating IP ID""" + + created_at: datetime + """Datetime when the floating IP was created""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + fixed_ip_address: Optional[str] = None + """IP address of the port the floating IP is attached to""" + + floating_ip_address: Optional[str] = None + """IP Address of the floating IP""" + + instance: Optional[Instance] = None + """Instance the floating IP is attached to""" + + loadbalancer: Optional[LoadBalancer] = None + """Load balancer the floating IP is attached to""" + + port_id: Optional[str] = None + """Port ID""" + + project_id: int + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + router_id: Optional[str] = None + """Router ID""" + + status: Optional[FloatingIPStatus] = None + """Floating IP status. + + DOWN - unassigned (available). ACTIVE - attached to a port (in use). ERROR - + error state. + """ + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + updated_at: datetime + """Datetime when the floating IP was last updated""" diff --git a/src/gcore/types/cloud/floating_ip_list_params.py b/src/gcore/types/cloud/floating_ip_list_params.py new file mode 100644 index 00000000..4eb3b7e2 --- /dev/null +++ b/src/gcore/types/cloud/floating_ip_list_params.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from ..._types import SequenceNotStr +from .floating_ip_status import FloatingIPStatus + +__all__ = ["FloatingIPListParams"] + + +class FloatingIPListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + limit: int + """Optional. Limit the number of returned items""" + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ + + status: FloatingIPStatus + """Filter by floating IP status. + + DOWN - unassigned (available). ACTIVE - attached to a port (in use). ERROR - + error state. + """ + + tag_key: SequenceNotStr[str] + """Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2""" + + tag_key_value: str + """Optional. Filter by tag key-value pairs.""" diff --git a/src/gcore/types/cloud/floating_ip_status.py b/src/gcore/types/cloud/floating_ip_status.py new file mode 100644 index 00000000..4027641e --- /dev/null +++ b/src/gcore/types/cloud/floating_ip_status.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["FloatingIPStatus"] + +FloatingIPStatus: TypeAlias = Literal["ACTIVE", "DOWN", "ERROR"] diff --git a/src/gcore/types/cloud/floating_ip_update_params.py b/src/gcore/types/cloud/floating_ip_update_params.py new file mode 100644 index 00000000..26bbcd02 --- /dev/null +++ b/src/gcore/types/cloud/floating_ip_update_params.py @@ -0,0 +1,49 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +from .tag_update_map_param import TagUpdateMapParam + +__all__ = ["FloatingIPUpdateParams"] + + +class FloatingIPUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + fixed_ip_address: Optional[str] + """Fixed IP address""" + + port_id: Optional[str] + """Port ID""" + + tags: Optional[TagUpdateMapParam] + """Update key-value tags using JSON Merge Patch semantics (RFC 7386). + + Provide key-value pairs to add or update tags. Set tag values to `null` to + remove tags. Unspecified tags remain unchanged. Read-only tags are always + preserved and cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + """ diff --git a/src/gcore/types/cloud/gpu_baremetal/__init__.py b/src/gcore/types/cloud/gpu_baremetal/__init__.py new file mode 100644 index 00000000..baff756f --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/__init__.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .cluster_list_params import ClusterListParams as ClusterListParams +from .cluster_action_params import ClusterActionParams as ClusterActionParams +from .cluster_create_params import ClusterCreateParams as ClusterCreateParams +from .cluster_delete_params import ClusterDeleteParams as ClusterDeleteParams +from .cluster_resize_params import ClusterResizeParams as ClusterResizeParams +from .gpu_baremetal_cluster import GPUBaremetalCluster as GPUBaremetalCluster +from .cluster_rebuild_params import ClusterRebuildParams as ClusterRebuildParams diff --git a/src/gcore/types/cloud/gpu_baremetal/cluster_action_params.py b/src/gcore/types/cloud/gpu_baremetal/cluster_action_params.py new file mode 100644 index 00000000..e3208874 --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/cluster_action_params.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +from ..tag_update_map_param import TagUpdateMapParam + +__all__ = ["ClusterActionParams"] + + +class ClusterActionParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["update_tags"]] + """Action name""" + + tags: Required[Optional[TagUpdateMapParam]] + """Update key-value tags using JSON Merge Patch semantics (RFC 7386). + + Provide key-value pairs to add or update tags. Set tag values to `null` to + remove tags. Unspecified tags remain unchanged. Read-only tags are always + preserved and cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + """ diff --git a/src/gcore/types/cloud/gpu_baremetal/cluster_create_params.py b/src/gcore/types/cloud/gpu_baremetal/cluster_create_params.py new file mode 100644 index 00000000..d2b5284b --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/cluster_create_params.py @@ -0,0 +1,166 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "ClusterCreateParams", + "ServersSettings", + "ServersSettingsInterface", + "ServersSettingsInterfaceExternalInterfaceInputSerializer", + "ServersSettingsInterfaceSubnetInterfaceInputSerializer", + "ServersSettingsInterfaceSubnetInterfaceInputSerializerFloatingIP", + "ServersSettingsInterfaceAnySubnetInterfaceInputSerializer", + "ServersSettingsInterfaceAnySubnetInterfaceInputSerializerFloatingIP", + "ServersSettingsCredentials", + "ServersSettingsFileShare", + "ServersSettingsSecurityGroup", +] + + +class ClusterCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + flavor: Required[str] + """Cluster flavor ID""" + + image_id: Required[str] + """System image ID""" + + name: Required[str] + """Cluster name""" + + servers_count: Required[int] + """Number of servers in the cluster""" + + servers_settings: Required[ServersSettings] + """Configuration settings for the servers in the cluster""" + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + +class ServersSettingsInterfaceExternalInterfaceInputSerializer(TypedDict, total=False): + type: Required[Literal["external"]] + + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6, or use dual stack.""" + + name: str + """Interface name""" + + +class ServersSettingsInterfaceSubnetInterfaceInputSerializerFloatingIP(TypedDict, total=False): + """Floating IP config for this subnet attachment""" + + source: Required[Literal["new"]] + + +class ServersSettingsInterfaceSubnetInterfaceInputSerializer(TypedDict, total=False): + network_id: Required[str] + """Network ID the subnet belongs to. Port will be plugged in this network""" + + subnet_id: Required[str] + """Port is assigned an IP address from this subnet""" + + type: Required[Literal["subnet"]] + + floating_ip: ServersSettingsInterfaceSubnetInterfaceInputSerializerFloatingIP + """Floating IP config for this subnet attachment""" + + name: str + """Interface name""" + + +class ServersSettingsInterfaceAnySubnetInterfaceInputSerializerFloatingIP(TypedDict, total=False): + """Floating IP config for this subnet attachment""" + + source: Required[Literal["new"]] + + +class ServersSettingsInterfaceAnySubnetInterfaceInputSerializer(TypedDict, total=False): + network_id: Required[str] + """Network ID the subnet belongs to. Port will be plugged in this network""" + + type: Required[Literal["any_subnet"]] + + floating_ip: ServersSettingsInterfaceAnySubnetInterfaceInputSerializerFloatingIP + """Floating IP config for this subnet attachment""" + + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6, or use dual stack""" + + name: str + """Interface name""" + + +ServersSettingsInterface: TypeAlias = Union[ + ServersSettingsInterfaceExternalInterfaceInputSerializer, + ServersSettingsInterfaceSubnetInterfaceInputSerializer, + ServersSettingsInterfaceAnySubnetInterfaceInputSerializer, +] + + +class ServersSettingsCredentials(TypedDict, total=False): + """Optional server access credentials""" + + password: str + """Used to set the password for the specified 'username' on Linux instances. + + If 'username' is not provided, the password is applied to the default user of + the image. Mutually exclusive with 'user_data' - only one can be specified. + """ + + ssh_key_name: str + """ + Specifies the name of the SSH keypair, created via the + [/v1/`ssh_keys` endpoint](/docs/api-reference/cloud/ssh-keys/add-or-generate-ssh-key). + """ + + username: str + """The 'username' and 'password' fields create a new user on the system""" + + +class ServersSettingsFileShare(TypedDict, total=False): + id: Required[str] + """Unique identifier of the file share in UUID format.""" + + mount_path: Required[str] + """Absolute mount path inside the system where the file share will be mounted.""" + + +class ServersSettingsSecurityGroup(TypedDict, total=False): + id: Required[str] + """Resource ID""" + + +class ServersSettings(TypedDict, total=False): + """Configuration settings for the servers in the cluster""" + + interfaces: Required[Iterable[ServersSettingsInterface]] + """Subnet IPs and floating IPs""" + + credentials: ServersSettingsCredentials + """Optional server access credentials""" + + file_shares: Iterable[ServersSettingsFileShare] + """List of file shares to be mounted across the cluster.""" + + security_groups: Iterable[ServersSettingsSecurityGroup] + """List of security groups UUIDs""" + + user_data: str + """Optional custom user data (Base64-encoded)""" diff --git a/src/gcore/types/cloud/gpu_baremetal/cluster_delete_params.py b/src/gcore/types/cloud/gpu_baremetal/cluster_delete_params.py new file mode 100644 index 00000000..97104a24 --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/cluster_delete_params.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["ClusterDeleteParams"] + + +class ClusterDeleteParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + all_floating_ips: bool + """ + Flag indicating whether the floating ips associated with server / cluster are + deleted + """ + + all_reserved_fixed_ips: bool + """ + Flag indicating whether the reserved fixed ips associated with server / cluster + are deleted + """ + + floating_ip_ids: SequenceNotStr[str] + """Optional list of floating ips to be deleted""" + + reserved_fixed_ip_ids: SequenceNotStr[str] + """Optional list of reserved fixed ips to be deleted""" diff --git a/src/gcore/types/cloud/gpu_baremetal/cluster_list_params.py b/src/gcore/types/cloud/gpu_baremetal/cluster_list_params.py new file mode 100644 index 00000000..c96a3a7e --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/cluster_list_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, TypedDict + +__all__ = ["ClusterListParams"] + + +class ClusterListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + limit: int + """Limit of items on a single page""" + + managed_by: List[Literal["k8s", "user"]] + """Specifies the entity responsible for managing the resource. + + - `user`: The resource (cluster) is created and maintained directly by the user. + - `k8s`: The resource is created and maintained automatically by Managed + Kubernetes service + """ + + offset: int + """Offset in results list""" diff --git a/src/gcore/types/cloud/gpu_baremetal/cluster_rebuild_params.py b/src/gcore/types/cloud/gpu_baremetal/cluster_rebuild_params.py new file mode 100644 index 00000000..f9fe6f9d --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/cluster_rebuild_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["ClusterRebuildParams"] + + +class ClusterRebuildParams(TypedDict, total=False): + project_id: int + + region_id: int + + nodes: Required[SequenceNotStr[str]] + """List of nodes uuids to be rebuild""" + + image_id: Optional[str] + """AI GPU image ID""" + + user_data: Optional[str] + """ + String in base64 format.Examples of the `user_data`: + https://cloudinit.readthedocs.io/en/latest/topics/examples.html + """ diff --git a/src/gcore/types/cloud/gpu_baremetal/cluster_resize_params.py b/src/gcore/types/cloud/gpu_baremetal/cluster_resize_params.py new file mode 100644 index 00000000..cb9f2211 --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/cluster_resize_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ClusterResizeParams"] + + +class ClusterResizeParams(TypedDict, total=False): + project_id: int + + region_id: int + + instances_count: Required[int] + """Resized (total) number of instances""" diff --git a/src/gcore/types/cloud/gpu_baremetal/clusters/__init__.py b/src/gcore/types/cloud/gpu_baremetal/clusters/__init__.py new file mode 100644 index 00000000..7929f325 --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/clusters/__init__.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .flavor_list_params import FlavorListParams as FlavorListParams +from .server_list_params import ServerListParams as ServerListParams +from .image_upload_params import ImageUploadParams as ImageUploadParams +from .gpu_baremetal_flavor import GPUBaremetalFlavor as GPUBaremetalFlavor +from .server_delete_params import ServerDeleteParams as ServerDeleteParams +from .interface_attach_params import InterfaceAttachParams as InterfaceAttachParams +from .interface_detach_params import InterfaceDetachParams as InterfaceDetachParams +from .gpu_baremetal_flavor_list import GPUBaremetalFlavorList as GPUBaremetalFlavorList +from .gpu_baremetal_cluster_server import GPUBaremetalClusterServer as GPUBaremetalClusterServer +from .gpu_baremetal_cluster_server_v1 import GPUBaremetalClusterServerV1 as GPUBaremetalClusterServerV1 +from .gpu_baremetal_cluster_server_v1_list import GPUBaremetalClusterServerV1List as GPUBaremetalClusterServerV1List diff --git a/src/gcore/types/cloud/gpu_baremetal/clusters/flavor_list_params.py b/src/gcore/types/cloud/gpu_baremetal/clusters/flavor_list_params.py new file mode 100644 index 00000000..febeb592 --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/clusters/flavor_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["FlavorListParams"] + + +class FlavorListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + hide_disabled: bool + """Set to `true` to remove the disabled flavors from the response.""" + + include_prices: bool + """Set to `true` if the response should include flavor prices.""" diff --git a/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_cluster_server.py b/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_cluster_server.py new file mode 100644 index 00000000..ff1e581f --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_cluster_server.py @@ -0,0 +1,77 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ...tag import Tag +from ....._models import BaseModel + +__all__ = ["GPUBaremetalClusterServer", "SecurityGroup"] + + +class SecurityGroup(BaseModel): + id: str + """Security group ID""" + + name: str + """Security group name""" + + +class GPUBaremetalClusterServer(BaseModel): + id: str + """Server unique identifier""" + + created_at: datetime + """Server creation date and time""" + + flavor: str + """Unique flavor identifier""" + + image_id: Optional[str] = None + """Server's image UUID""" + + ip_addresses: List[str] + """List of IP addresses""" + + name: str + """Server's name generated using cluster's name""" + + security_groups: List[SecurityGroup] + """Security groups""" + + ssh_key_name: Optional[str] = None + """SSH key pair assigned to the server""" + + status: Literal[ + "ACTIVE", + "BUILD", + "DELETED", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PASSWORD", + "PAUSED", + "REBOOT", + "REBUILD", + "RESCUE", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "UNKNOWN", + "VERIFY_RESIZE", + ] + """Current server status""" + + tags: List[Tag] + """User defined tags""" + + task_id: Optional[str] = None + """Identifier of the task currently modifying the GPU cluster""" + + updated_at: datetime + """Server update date and time""" diff --git a/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_cluster_server_v1.py b/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_cluster_server_v1.py new file mode 100644 index 00000000..9e44be1e --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_cluster_server_v1.py @@ -0,0 +1,204 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, TypeAlias + +from ...tag import Tag +from ....._models import BaseModel +from ...ddos_profile import DDOSProfile +from ...fixed_address import FixedAddress +from ...blackhole_port import BlackholePort +from ...floating_address import FloatingAddress +from ...instance_isolation import InstanceIsolation +from ...fixed_address_short import FixedAddressShort + +__all__ = [ + "GPUBaremetalClusterServerV1", + "Address", + "FixedIPAssignment", + "Flavor", + "FlavorHardwareDescription", + "SecurityGroup", +] + +Address: TypeAlias = Union[FloatingAddress, FixedAddressShort, FixedAddress] + + +class FixedIPAssignment(BaseModel): + external: bool + """Is network external""" + + ip_address: str + """Ip address""" + + subnet_id: str + """Interface subnet id""" + + +class FlavorHardwareDescription(BaseModel): + """Additional hardware description""" + + cpu: str + """Human-readable CPU description""" + + disk: str + """Human-readable disk description""" + + gpu: str + """Human-readable GPU description""" + + license: str + """If the flavor is licensed, this field contains the license type""" + + network: str + """Human-readable NIC description""" + + ram: str + """Human-readable RAM description""" + + +class Flavor(BaseModel): + """Flavor""" + + architecture: str + """CPU architecture""" + + flavor_id: str + """Flavor ID is the same as name""" + + flavor_name: str + """Flavor name""" + + hardware_description: FlavorHardwareDescription + """Additional hardware description""" + + os_type: str + """Operating system""" + + ram: int + """RAM size in MiB""" + + resource_class: str + """Flavor resource class for mapping to hardware capacity""" + + vcpus: int + """Virtual CPU count. For bare metal flavors, it's a physical CPU count""" + + +class SecurityGroup(BaseModel): + name: str + """Name.""" + + +class GPUBaremetalClusterServerV1(BaseModel): + id: str + """GPU server ID""" + + addresses: Dict[str, List[Address]] + """Map of `network_name` to list of addresses in that network""" + + blackhole_ports: List[BlackholePort] + """IP addresses of the instances that are blackholed by DDoS mitigation system""" + + created_at: datetime + """Datetime when GPU server was created""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + ddos_profile: Optional[DDOSProfile] = None + """Advanced DDoS protection profile. + + It is always `null` if query parameter `with_ddos=true` is not set. + """ + + fixed_ip_assignments: Optional[List[FixedIPAssignment]] = None + """Fixed IP assigned to instance""" + + flavor: Flavor + """Flavor""" + + instance_description: Optional[str] = None + """Instance description""" + + instance_isolation: Optional[InstanceIsolation] = None + """Instance isolation information""" + + name: str + """GPU server name""" + + project_id: int + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + security_groups: List[SecurityGroup] + """Security groups""" + + ssh_key_name: Optional[str] = None + """SSH key name assigned to instance""" + + status: Literal[ + "ACTIVE", + "BUILD", + "DELETED", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PASSWORD", + "PAUSED", + "REBOOT", + "REBUILD", + "RESCUE", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "UNKNOWN", + "VERIFY_RESIZE", + ] + """Instance status""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + task_state: Optional[str] = None + """Task state""" + + vm_state: Literal[ + "active", + "building", + "deleted", + "error", + "paused", + "rescued", + "resized", + "shelved", + "shelved_offloaded", + "soft-deleted", + "stopped", + "suspended", + ] + """Virtual machine state (active)""" diff --git a/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_cluster_server_v1_list.py b/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_cluster_server_v1_list.py new file mode 100644 index 00000000..b3599d3a --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_cluster_server_v1_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ....._models import BaseModel +from .gpu_baremetal_cluster_server_v1 import GPUBaremetalClusterServerV1 + +__all__ = ["GPUBaremetalClusterServerV1List"] + + +class GPUBaremetalClusterServerV1List(BaseModel): + count: int + """Number of objects""" + + results: List[GPUBaremetalClusterServerV1] + """Objects""" diff --git a/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_flavor.py b/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_flavor.py new file mode 100644 index 00000000..44757b06 --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_flavor.py @@ -0,0 +1,181 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal, TypeAlias + +from ....._models import BaseModel + +__all__ = [ + "GPUBaremetalFlavor", + "GPUBaremetalFlavorSerializerWithoutPrice", + "GPUBaremetalFlavorSerializerWithoutPriceHardwareDescription", + "GPUBaremetalFlavorSerializerWithoutPriceHardwareProperties", + "GPUBaremetalFlavorSerializerWithoutPriceSupportedFeatures", + "GPUBaremetalFlavorSerializerWithPrices", + "GPUBaremetalFlavorSerializerWithPricesHardwareDescription", + "GPUBaremetalFlavorSerializerWithPricesHardwareProperties", + "GPUBaremetalFlavorSerializerWithPricesPrice", + "GPUBaremetalFlavorSerializerWithPricesSupportedFeatures", +] + + +class GPUBaremetalFlavorSerializerWithoutPriceHardwareDescription(BaseModel): + """Additional bare metal hardware description""" + + cpu: str + """Human-readable CPU description""" + + disk: str + """Human-readable disk description""" + + gpu: str + """Human-readable GPU description""" + + network: str + """Human-readable NIC description""" + + ram: str + """Human-readable RAM description""" + + +class GPUBaremetalFlavorSerializerWithoutPriceHardwareProperties(BaseModel): + """Additional bare metal hardware properties""" + + gpu_count: Optional[int] = None + """The total count of available GPUs.""" + + gpu_manufacturer: Optional[str] = None + """The manufacturer of the graphics processing GPU""" + + gpu_model: Optional[str] = None + """GPU model""" + + nic_eth: Optional[str] = None + """The configuration of the Ethernet ports""" + + nic_ib: Optional[str] = None + """The configuration of the InfiniBand ports""" + + +class GPUBaremetalFlavorSerializerWithoutPriceSupportedFeatures(BaseModel): + """Set of enabled features based on the flavor's type and configuration""" + + security_groups: bool + + +class GPUBaremetalFlavorSerializerWithoutPrice(BaseModel): + architecture: Optional[str] = None + """Flavor architecture type""" + + capacity: int + """Number of available instances of given flavor for the client""" + + disabled: bool + """If the flavor is disabled, new resources cannot be created using this flavor.""" + + hardware_description: GPUBaremetalFlavorSerializerWithoutPriceHardwareDescription + """Additional bare metal hardware description""" + + hardware_properties: GPUBaremetalFlavorSerializerWithoutPriceHardwareProperties + """Additional bare metal hardware properties""" + + name: str + """Flavor name""" + + reserved_capacity: int + """Number of available instances of given flavor from reservations""" + + supported_features: GPUBaremetalFlavorSerializerWithoutPriceSupportedFeatures + """Set of enabled features based on the flavor's type and configuration""" + + +class GPUBaremetalFlavorSerializerWithPricesHardwareDescription(BaseModel): + """Additional bare metal hardware description""" + + cpu: str + """Human-readable CPU description""" + + disk: str + """Human-readable disk description""" + + gpu: str + """Human-readable GPU description""" + + network: str + """Human-readable NIC description""" + + ram: str + """Human-readable RAM description""" + + +class GPUBaremetalFlavorSerializerWithPricesHardwareProperties(BaseModel): + """Additional bare metal hardware properties""" + + gpu_count: Optional[int] = None + """The total count of available GPUs.""" + + gpu_manufacturer: Optional[str] = None + """The manufacturer of the graphics processing GPU""" + + gpu_model: Optional[str] = None + """GPU model""" + + nic_eth: Optional[str] = None + """The configuration of the Ethernet ports""" + + nic_ib: Optional[str] = None + """The configuration of the InfiniBand ports""" + + +class GPUBaremetalFlavorSerializerWithPricesPrice(BaseModel): + """Flavor price""" + + currency_code: Optional[str] = None + """Currency code. Shown if the `include_prices` query parameter if set to true""" + + price_per_hour: Optional[float] = None + """Price per hour. Shown if the `include_prices` query parameter if set to true""" + + price_per_month: Optional[float] = None + """Price per month. Shown if the `include_prices` query parameter if set to true""" + + price_status: Optional[Literal["error", "hide", "show"]] = None + """Price status for the UI""" + + +class GPUBaremetalFlavorSerializerWithPricesSupportedFeatures(BaseModel): + """Set of enabled features based on the flavor's type and configuration""" + + security_groups: bool + + +class GPUBaremetalFlavorSerializerWithPrices(BaseModel): + architecture: Optional[str] = None + """Flavor architecture type""" + + capacity: int + """Number of available instances of given flavor for the client""" + + disabled: bool + """If the flavor is disabled, new resources cannot be created using this flavor.""" + + hardware_description: GPUBaremetalFlavorSerializerWithPricesHardwareDescription + """Additional bare metal hardware description""" + + hardware_properties: GPUBaremetalFlavorSerializerWithPricesHardwareProperties + """Additional bare metal hardware properties""" + + name: str + """Flavor name""" + + price: GPUBaremetalFlavorSerializerWithPricesPrice + """Flavor price""" + + reserved_capacity: int + """Number of available instances of given flavor from reservations""" + + supported_features: GPUBaremetalFlavorSerializerWithPricesSupportedFeatures + """Set of enabled features based on the flavor's type and configuration""" + + +GPUBaremetalFlavor: TypeAlias = Union[GPUBaremetalFlavorSerializerWithoutPrice, GPUBaremetalFlavorSerializerWithPrices] diff --git a/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_flavor_list.py b/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_flavor_list.py new file mode 100644 index 00000000..785daffd --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/clusters/gpu_baremetal_flavor_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ....._models import BaseModel +from .gpu_baremetal_flavor import GPUBaremetalFlavor + +__all__ = ["GPUBaremetalFlavorList"] + + +class GPUBaremetalFlavorList(BaseModel): + count: int + """Number of objects""" + + results: List[GPUBaremetalFlavor] + """Objects""" diff --git a/src/gcore/types/cloud/gpu_baremetal/clusters/image_upload_params.py b/src/gcore/types/cloud/gpu_baremetal/clusters/image_upload_params.py new file mode 100644 index 00000000..269dfd76 --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/clusters/image_upload_params.py @@ -0,0 +1,56 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ImageUploadParams"] + + +class ImageUploadParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: Required[str] + """Image name""" + + url: Required[str] + """Image URL""" + + architecture: Optional[Literal["aarch64", "x86_64"]] + """Image architecture type: aarch64, `x86_64`""" + + cow_format: bool + """ + When True, image cannot be deleted unless all volumes, created from it, are + deleted. + """ + + hw_firmware_type: Optional[Literal["bios", "uefi"]] + """Specifies the type of firmware with which to boot the guest.""" + + os_distro: Optional[str] + """OS Distribution, i.e. Debian, CentOS, Ubuntu, CoreOS etc.""" + + os_type: Optional[Literal["linux", "windows"]] + """The operating system installed on the image. Linux by default""" + + os_version: Optional[str] + """OS version, i.e. 19.04 (for Ubuntu) or 9.4 for Debian""" + + ssh_key: Literal["allow", "deny", "required"] + """Permission to use a ssh key in instances""" + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ diff --git a/src/gcore/types/cloud/gpu_baremetal/clusters/interface_attach_params.py b/src/gcore/types/cloud/gpu_baremetal/clusters/interface_attach_params.py new file mode 100644 index 00000000..f3a3c26e --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/clusters/interface_attach_params.py @@ -0,0 +1,269 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "InterfaceAttachParams", + "NewInterfaceExternalExtendSchemaWithDDOS", + "NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile", + "NewInterfaceExternalExtendSchemaWithDdosddosProfileField", + "NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup", + "NewInterfaceSpecificSubnetSchema", + "NewInterfaceSpecificSubnetSchemaDDOSProfile", + "NewInterfaceSpecificSubnetSchemaDDOSProfileField", + "NewInterfaceSpecificSubnetSchemaSecurityGroup", + "NewInterfaceAnySubnetSchema", + "NewInterfaceAnySubnetSchemaDDOSProfile", + "NewInterfaceAnySubnetSchemaDDOSProfileField", + "NewInterfaceAnySubnetSchemaSecurityGroup", + "NewInterfaceReservedFixedIPSchema", + "NewInterfaceReservedFixedIPSchemaDDOSProfile", + "NewInterfaceReservedFixedIPSchemaDDOSProfileField", + "NewInterfaceReservedFixedIPSchemaSecurityGroup", +] + + +class NewInterfaceExternalExtendSchemaWithDDOS(TypedDict, total=False): + project_id: int + + region_id: int + + ddos_profile: NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile + """Advanced DDoS protection.""" + + interface_name: str + """Interface name""" + + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6 or use dual stack.""" + + port_group: int + """Each group will be added to the separate trunk.""" + + security_groups: Iterable[NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + """List of security group IDs""" + + type: str + """Must be 'external'. Union tag""" + + +class NewInterfaceExternalExtendSchemaWithDdosddosProfileField(TypedDict, total=False): + base_field: Optional[int] + """ID of DDoS profile field""" + + field_name: Optional[str] + """Name of DDoS profile field""" + + field_value: object + """Complex value. Only one of 'value' or 'field_value' must be specified.""" + + value: Optional[str] + """Basic type value. Only one of 'value' or 'field_value' must be specified.""" + + +class NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile(TypedDict, total=False): + """Advanced DDoS protection.""" + + profile_template: Required[int] + """DDoS profile template ID.""" + + fields: Iterable[NewInterfaceExternalExtendSchemaWithDdosddosProfileField] + """Protection parameters.""" + + profile_template_name: str + """DDoS profile template name.""" + + +class NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup(TypedDict, total=False): + """MandatoryIdSchema schema""" + + id: Required[str] + """Resource ID""" + + +class NewInterfaceSpecificSubnetSchema(TypedDict, total=False): + project_id: int + + region_id: int + + subnet_id: Required[str] + """Port will get an IP address from this subnet""" + + ddos_profile: NewInterfaceSpecificSubnetSchemaDDOSProfile + """Advanced DDoS protection.""" + + interface_name: str + """Interface name""" + + port_group: int + """Each group will be added to the separate trunk.""" + + security_groups: Iterable[NewInterfaceSpecificSubnetSchemaSecurityGroup] + """List of security group IDs""" + + type: str + """Must be 'subnet'""" + + +class NewInterfaceSpecificSubnetSchemaDDOSProfileField(TypedDict, total=False): + base_field: Optional[int] + """ID of DDoS profile field""" + + field_name: Optional[str] + """Name of DDoS profile field""" + + field_value: object + """Complex value. Only one of 'value' or 'field_value' must be specified.""" + + value: Optional[str] + """Basic type value. Only one of 'value' or 'field_value' must be specified.""" + + +class NewInterfaceSpecificSubnetSchemaDDOSProfile(TypedDict, total=False): + """Advanced DDoS protection.""" + + profile_template: Required[int] + """DDoS profile template ID.""" + + fields: Iterable[NewInterfaceSpecificSubnetSchemaDDOSProfileField] + """Protection parameters.""" + + profile_template_name: str + """DDoS profile template name.""" + + +class NewInterfaceSpecificSubnetSchemaSecurityGroup(TypedDict, total=False): + """MandatoryIdSchema schema""" + + id: Required[str] + """Resource ID""" + + +class NewInterfaceAnySubnetSchema(TypedDict, total=False): + project_id: int + + region_id: int + + network_id: Required[str] + """Port will get an IP address in this network subnet""" + + ddos_profile: NewInterfaceAnySubnetSchemaDDOSProfile + """Advanced DDoS protection.""" + + interface_name: str + """Interface name""" + + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6 or use dual stack.""" + + port_group: int + """Each group will be added to the separate trunk.""" + + security_groups: Iterable[NewInterfaceAnySubnetSchemaSecurityGroup] + """List of security group IDs""" + + type: str + """Must be 'any_subnet'""" + + +class NewInterfaceAnySubnetSchemaDDOSProfileField(TypedDict, total=False): + base_field: Optional[int] + """ID of DDoS profile field""" + + field_name: Optional[str] + """Name of DDoS profile field""" + + field_value: object + """Complex value. Only one of 'value' or 'field_value' must be specified.""" + + value: Optional[str] + """Basic type value. Only one of 'value' or 'field_value' must be specified.""" + + +class NewInterfaceAnySubnetSchemaDDOSProfile(TypedDict, total=False): + """Advanced DDoS protection.""" + + profile_template: Required[int] + """DDoS profile template ID.""" + + fields: Iterable[NewInterfaceAnySubnetSchemaDDOSProfileField] + """Protection parameters.""" + + profile_template_name: str + """DDoS profile template name.""" + + +class NewInterfaceAnySubnetSchemaSecurityGroup(TypedDict, total=False): + """MandatoryIdSchema schema""" + + id: Required[str] + """Resource ID""" + + +class NewInterfaceReservedFixedIPSchema(TypedDict, total=False): + project_id: int + + region_id: int + + port_id: Required[str] + """Port ID""" + + ddos_profile: NewInterfaceReservedFixedIPSchemaDDOSProfile + """Advanced DDoS protection.""" + + interface_name: str + """Interface name""" + + port_group: int + """Each group will be added to the separate trunk.""" + + security_groups: Iterable[NewInterfaceReservedFixedIPSchemaSecurityGroup] + """List of security group IDs""" + + type: str + """Must be 'reserved_fixed_ip'. Union tag""" + + +class NewInterfaceReservedFixedIPSchemaDDOSProfileField(TypedDict, total=False): + base_field: Optional[int] + """ID of DDoS profile field""" + + field_name: Optional[str] + """Name of DDoS profile field""" + + field_value: object + """Complex value. Only one of 'value' or 'field_value' must be specified.""" + + value: Optional[str] + """Basic type value. Only one of 'value' or 'field_value' must be specified.""" + + +class NewInterfaceReservedFixedIPSchemaDDOSProfile(TypedDict, total=False): + """Advanced DDoS protection.""" + + profile_template: Required[int] + """DDoS profile template ID.""" + + fields: Iterable[NewInterfaceReservedFixedIPSchemaDDOSProfileField] + """Protection parameters.""" + + profile_template_name: str + """DDoS profile template name.""" + + +class NewInterfaceReservedFixedIPSchemaSecurityGroup(TypedDict, total=False): + """MandatoryIdSchema schema""" + + id: Required[str] + """Resource ID""" + + +InterfaceAttachParams: TypeAlias = Union[ + NewInterfaceExternalExtendSchemaWithDDOS, + NewInterfaceSpecificSubnetSchema, + NewInterfaceAnySubnetSchema, + NewInterfaceReservedFixedIPSchema, +] diff --git a/src/gcore/types/cloud/gpu_baremetal/clusters/interface_detach_params.py b/src/gcore/types/cloud/gpu_baremetal/clusters/interface_detach_params.py new file mode 100644 index 00000000..5f092a84 --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/clusters/interface_detach_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["InterfaceDetachParams"] + + +class InterfaceDetachParams(TypedDict, total=False): + project_id: int + + region_id: int + + ip_address: Required[str] + """IP address""" + + port_id: Required[str] + """ID of the port""" diff --git a/src/gcore/types/cloud/gpu_baremetal/clusters/server_delete_params.py b/src/gcore/types/cloud/gpu_baremetal/clusters/server_delete_params.py new file mode 100644 index 00000000..534d22f7 --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/clusters/server_delete_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ServerDeleteParams"] + + +class ServerDeleteParams(TypedDict, total=False): + project_id: int + + region_id: int + + cluster_id: Required[str] + + delete_floatings: bool + """Set False if you do not want to delete assigned floating IPs. + + By default, it's True. + """ diff --git a/src/gcore/types/cloud/gpu_baremetal/clusters/server_list_params.py b/src/gcore/types/cloud/gpu_baremetal/clusters/server_list_params.py new file mode 100644 index 00000000..89f4cb6d --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/clusters/server_list_params.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Literal, Annotated, TypedDict + +from ....._types import SequenceNotStr +from ....._utils import PropertyInfo + +__all__ = ["ServerListParams"] + + +class ServerListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + changed_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """ + Filters the results to include only servers whose last change timestamp is less + than the specified datetime. Format: ISO 8601. + """ + + changed_since: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """ + Filters the results to include only servers whose last change timestamp is + greater than or equal to the specified datetime. Format: ISO 8601. + """ + + ip_address: str + """Filter servers by ip address.""" + + limit: int + """Limit of items on a single page""" + + name: str + """Filter servers by name. + + You can provide a full or partial name, servers with matching names will be + returned. For example, entering 'test' will return all servers that contain + 'test' in their name. + """ + + offset: int + """Offset in results list""" + + order_by: Literal["created_at.asc", "created_at.desc", "status.asc", "status.desc"] + """Order field""" + + status: Literal[ + "ACTIVE", + "BUILD", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PAUSED", + "REBOOT", + "REBUILD", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "VERIFY_RESIZE", + ] + """Filters servers by status.""" + + uuids: SequenceNotStr[str] + """Filter servers by uuid.""" diff --git a/src/gcore/types/cloud/gpu_baremetal/gpu_baremetal_cluster.py b/src/gcore/types/cloud/gpu_baremetal/gpu_baremetal_cluster.py new file mode 100644 index 00000000..5eb7f5da --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal/gpu_baremetal_cluster.py @@ -0,0 +1,167 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from ..tag import Tag +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "GPUBaremetalCluster", + "ServersSettings", + "ServersSettingsFileShare", + "ServersSettingsInterface", + "ServersSettingsInterfaceExternalInterfaceOutputSerializer", + "ServersSettingsInterfaceSubnetInterfaceOutputSerializer", + "ServersSettingsInterfaceSubnetInterfaceOutputSerializerFloatingIP", + "ServersSettingsInterfaceAnySubnetInterfaceOutputSerializer", + "ServersSettingsInterfaceAnySubnetInterfaceOutputSerializerFloatingIP", + "ServersSettingsSecurityGroup", +] + + +class ServersSettingsFileShare(BaseModel): + id: str + """Unique identifier of the file share in UUID format.""" + + mount_path: str + """Absolute mount path inside the system where the file share will be mounted.""" + + +class ServersSettingsInterfaceExternalInterfaceOutputSerializer(BaseModel): + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6, or use dual stack.""" + + name: Optional[str] = None + """Interface name""" + + type: Literal["external"] + + +class ServersSettingsInterfaceSubnetInterfaceOutputSerializerFloatingIP(BaseModel): + """Floating IP config for this subnet attachment""" + + source: Literal["new"] + + +class ServersSettingsInterfaceSubnetInterfaceOutputSerializer(BaseModel): + floating_ip: Optional[ServersSettingsInterfaceSubnetInterfaceOutputSerializerFloatingIP] = None + """Floating IP config for this subnet attachment""" + + name: Optional[str] = None + """Interface name""" + + network_id: str + """Network ID the subnet belongs to. Port will be plugged in this network""" + + subnet_id: str + """Port is assigned an IP address from this subnet""" + + type: Literal["subnet"] + + +class ServersSettingsInterfaceAnySubnetInterfaceOutputSerializerFloatingIP(BaseModel): + """Floating IP config for this subnet attachment""" + + source: Literal["new"] + + +class ServersSettingsInterfaceAnySubnetInterfaceOutputSerializer(BaseModel): + floating_ip: Optional[ServersSettingsInterfaceAnySubnetInterfaceOutputSerializerFloatingIP] = None + """Floating IP config for this subnet attachment""" + + ip_address: Optional[str] = None + """Fixed IP address""" + + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6, or use dual stack""" + + name: Optional[str] = None + """Interface name""" + + network_id: str + """Network ID the subnet belongs to. Port will be plugged in this network""" + + type: Literal["any_subnet"] + + +ServersSettingsInterface: TypeAlias = Annotated[ + Union[ + ServersSettingsInterfaceExternalInterfaceOutputSerializer, + ServersSettingsInterfaceSubnetInterfaceOutputSerializer, + ServersSettingsInterfaceAnySubnetInterfaceOutputSerializer, + ], + PropertyInfo(discriminator="type"), +] + + +class ServersSettingsSecurityGroup(BaseModel): + id: str + """Security group ID""" + + name: str + """Security group name""" + + +class ServersSettings(BaseModel): + file_shares: List[ServersSettingsFileShare] + """List of file shares mounted across the cluster.""" + + interfaces: List[ServersSettingsInterface] + + security_groups: List[ServersSettingsSecurityGroup] + """Security groups""" + + ssh_key_name: Optional[str] = None + """SSH key name""" + + user_data: Optional[str] = None + """Optional custom user data""" + + +class GPUBaremetalCluster(BaseModel): + id: str + """Cluster unique identifier""" + + created_at: datetime + """Cluster creation date time""" + + flavor: str + """Cluster flavor name""" + + image_id: str + """Image ID""" + + managed_by: Literal["k8s", "user"] + """User type managing the resource""" + + name: str + """Cluster name""" + + servers_count: int + """Cluster servers count""" + + servers_ids: List[str] + """List of cluster nodes""" + + servers_settings: ServersSettings + + status: Literal[ + "active", "creating", "degraded", "deleting", "error", "new", "rebooting", "rebuilding", "resizing", "shutoff" + ] + """Cluster status""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + updated_at: Optional[datetime] = None + """Cluster update date time""" diff --git a/src/gcore/types/cloud/gpu_image.py b/src/gcore/types/cloud/gpu_image.py new file mode 100644 index 00000000..31a90256 --- /dev/null +++ b/src/gcore/types/cloud/gpu_image.py @@ -0,0 +1,79 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from .tag import Tag +from ..._models import BaseModel + +__all__ = ["GPUImage"] + + +class GPUImage(BaseModel): + id: str + """Image ID""" + + created_at: datetime + """Datetime when the image was created""" + + min_disk: int + """Minimal boot volume required""" + + min_ram: int + """Minimal VM RAM required""" + + name: str + """Image name""" + + status: str + """Image status""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + updated_at: datetime + """Datetime when the image was updated""" + + visibility: str + """Image visibility. Globally visible images are public""" + + architecture: Optional[str] = None + """Image architecture type""" + + gpu_driver: Optional[str] = None + """Name of the GPU driver vendor""" + + gpu_driver_type: Optional[str] = None + """Type of the GPU driver""" + + gpu_driver_version: Optional[str] = None + """Version of the installed GPU driver""" + + os_distro: Optional[str] = None + """OS Distribution""" + + os_type: Optional[str] = None + """The operating system installed on the image""" + + os_version: Optional[str] = None + """OS version, i.e. 19.04 (for Ubuntu) or 9.4 for Debian""" + + size: Optional[int] = None + """Image size in bytes.""" + + ssh_key: Optional[str] = None + """Whether the image supports SSH key or not""" + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ diff --git a/src/gcore/types/cloud/gpu_image_list.py b/src/gcore/types/cloud/gpu_image_list.py new file mode 100644 index 00000000..d180ff92 --- /dev/null +++ b/src/gcore/types/cloud/gpu_image_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .gpu_image import GPUImage + +__all__ = ["GPUImageList"] + + +class GPUImageList(BaseModel): + count: int + """Number of objects""" + + results: List[GPUImage] + """Objects""" diff --git a/src/gcore/types/cloud/gpu_virtual/__init__.py b/src/gcore/types/cloud/gpu_virtual/__init__.py new file mode 100644 index 00000000..9c1abcb8 --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/__init__.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .cluster_list_params import ClusterListParams as ClusterListParams +from .gpu_virtual_cluster import GPUVirtualCluster as GPUVirtualCluster +from .cluster_action_params import ClusterActionParams as ClusterActionParams +from .cluster_create_params import ClusterCreateParams as ClusterCreateParams +from .cluster_delete_params import ClusterDeleteParams as ClusterDeleteParams +from .cluster_update_params import ClusterUpdateParams as ClusterUpdateParams diff --git a/src/gcore/types/cloud/gpu_virtual/cluster_action_params.py b/src/gcore/types/cloud/gpu_virtual/cluster_action_params.py new file mode 100644 index 00000000..e620f9ee --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/cluster_action_params.py @@ -0,0 +1,122 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..tag_update_map_param import TagUpdateMapParam + +__all__ = [ + "ClusterActionParams", + "StartVirtualGPUClusterSerializer", + "StopVirtualGPUClusterSerializer", + "SoftRebootVirtualGPUClusterSerializer", + "HardRebootVirtualGPUClusterSerializer", + "UpdateTagsGPUClusterSerializer", + "ResizeVirtualGPUClusterSerializer", +] + + +class StartVirtualGPUClusterSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["start"]] + """Action name""" + + +class StopVirtualGPUClusterSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["stop"]] + """Action name""" + + +class SoftRebootVirtualGPUClusterSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["soft_reboot"]] + """Action name""" + + +class HardRebootVirtualGPUClusterSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["hard_reboot"]] + """Action name""" + + +class UpdateTagsGPUClusterSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["update_tags"]] + """Action name""" + + tags: Required[Optional[TagUpdateMapParam]] + """Update key-value tags using JSON Merge Patch semantics (RFC 7386). + + Provide key-value pairs to add or update tags. Set tag values to `null` to + remove tags. Unspecified tags remain unchanged. Read-only tags are always + preserved and cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + """ + + +class ResizeVirtualGPUClusterSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["resize"]] + """Action name""" + + servers_count: Required[int] + """Requested servers count""" + + +ClusterActionParams: TypeAlias = Union[ + StartVirtualGPUClusterSerializer, + StopVirtualGPUClusterSerializer, + SoftRebootVirtualGPUClusterSerializer, + HardRebootVirtualGPUClusterSerializer, + UpdateTagsGPUClusterSerializer, + ResizeVirtualGPUClusterSerializer, +] diff --git a/src/gcore/types/cloud/gpu_virtual/cluster_create_params.py b/src/gcore/types/cloud/gpu_virtual/cluster_create_params.py new file mode 100644 index 00000000..a6b6e0b1 --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/cluster_create_params.py @@ -0,0 +1,221 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "ClusterCreateParams", + "ServersSettings", + "ServersSettingsInterface", + "ServersSettingsInterfaceExternalInterfaceInputSerializer", + "ServersSettingsInterfaceSubnetInterfaceInputSerializer", + "ServersSettingsInterfaceSubnetInterfaceInputSerializerFloatingIP", + "ServersSettingsInterfaceAnySubnetInterfaceInputSerializer", + "ServersSettingsInterfaceAnySubnetInterfaceInputSerializerFloatingIP", + "ServersSettingsVolume", + "ServersSettingsVolumeNewVolumeInputSerializer", + "ServersSettingsVolumeImageVolumeInputSerializer", + "ServersSettingsCredentials", + "ServersSettingsFileShare", + "ServersSettingsSecurityGroup", +] + + +class ClusterCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + flavor: Required[str] + """Cluster flavor ID""" + + name: Required[str] + """Cluster name""" + + servers_count: Required[int] + """Number of servers in the cluster""" + + servers_settings: Required[ServersSettings] + """Configuration settings for the servers in the cluster""" + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + +class ServersSettingsInterfaceExternalInterfaceInputSerializer(TypedDict, total=False): + type: Required[Literal["external"]] + + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6, or use dual stack.""" + + name: str + """Interface name""" + + +class ServersSettingsInterfaceSubnetInterfaceInputSerializerFloatingIP(TypedDict, total=False): + """Floating IP config for this subnet attachment""" + + source: Required[Literal["new"]] + + +class ServersSettingsInterfaceSubnetInterfaceInputSerializer(TypedDict, total=False): + network_id: Required[str] + """Network ID the subnet belongs to. Port will be plugged in this network""" + + subnet_id: Required[str] + """Port is assigned an IP address from this subnet""" + + type: Required[Literal["subnet"]] + + floating_ip: ServersSettingsInterfaceSubnetInterfaceInputSerializerFloatingIP + """Floating IP config for this subnet attachment""" + + name: str + """Interface name""" + + +class ServersSettingsInterfaceAnySubnetInterfaceInputSerializerFloatingIP(TypedDict, total=False): + """Floating IP config for this subnet attachment""" + + source: Required[Literal["new"]] + + +class ServersSettingsInterfaceAnySubnetInterfaceInputSerializer(TypedDict, total=False): + network_id: Required[str] + """Network ID the subnet belongs to. Port will be plugged in this network""" + + type: Required[Literal["any_subnet"]] + + floating_ip: ServersSettingsInterfaceAnySubnetInterfaceInputSerializerFloatingIP + """Floating IP config for this subnet attachment""" + + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6, or use dual stack""" + + name: str + """Interface name""" + + +ServersSettingsInterface: TypeAlias = Union[ + ServersSettingsInterfaceExternalInterfaceInputSerializer, + ServersSettingsInterfaceSubnetInterfaceInputSerializer, + ServersSettingsInterfaceAnySubnetInterfaceInputSerializer, +] + + +class ServersSettingsVolumeNewVolumeInputSerializer(TypedDict, total=False): + boot_index: Required[int] + """Boot index of the volume""" + + name: Required[str] + """Volume name""" + + size: Required[int] + """Volume size in GiB""" + + source: Required[Literal["new"]] + + type: Required[Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"]] + """Volume type""" + + delete_on_termination: bool + """Flag indicating whether the volume is deleted on instance termination""" + + tags: Dict[str, str] + """Tags associated with the volume""" + + +class ServersSettingsVolumeImageVolumeInputSerializer(TypedDict, total=False): + boot_index: Required[int] + """Boot index of the volume""" + + image_id: Required[str] + """Image ID for the volume""" + + name: Required[str] + """Volume name""" + + size: Required[int] + """Volume size in GiB""" + + source: Required[Literal["image"]] + + type: Required[Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"]] + """Volume type""" + + delete_on_termination: bool + """Flag indicating whether the volume is deleted on instance termination""" + + tags: Dict[str, str] + """Tags associated with the volume""" + + +ServersSettingsVolume: TypeAlias = Union[ + ServersSettingsVolumeNewVolumeInputSerializer, ServersSettingsVolumeImageVolumeInputSerializer +] + + +class ServersSettingsCredentials(TypedDict, total=False): + """Optional server access credentials""" + + password: str + """Used to set the password for the specified 'username' on Linux instances. + + If 'username' is not provided, the password is applied to the default user of + the image. Mutually exclusive with 'user_data' - only one can be specified. + """ + + ssh_key_name: str + """ + Specifies the name of the SSH keypair, created via the + [/v1/`ssh_keys` endpoint](/docs/api-reference/cloud/ssh-keys/add-or-generate-ssh-key). + """ + + username: str + """The 'username' and 'password' fields create a new user on the system""" + + +class ServersSettingsFileShare(TypedDict, total=False): + id: Required[str] + """Unique identifier of the file share in UUID format.""" + + mount_path: Required[str] + """Absolute mount path inside the system where the file share will be mounted.""" + + +class ServersSettingsSecurityGroup(TypedDict, total=False): + id: Required[str] + """Resource ID""" + + +class ServersSettings(TypedDict, total=False): + """Configuration settings for the servers in the cluster""" + + interfaces: Required[Iterable[ServersSettingsInterface]] + """Subnet IPs and floating IPs""" + + volumes: Required[Iterable[ServersSettingsVolume]] + """List of volumes""" + + credentials: ServersSettingsCredentials + """Optional server access credentials""" + + file_shares: Iterable[ServersSettingsFileShare] + """List of file shares to be mounted across the cluster.""" + + security_groups: Iterable[ServersSettingsSecurityGroup] + """List of security groups UUIDs""" + + user_data: str + """Optional custom user data (Base64-encoded)""" diff --git a/src/gcore/types/cloud/gpu_virtual/cluster_delete_params.py b/src/gcore/types/cloud/gpu_virtual/cluster_delete_params.py new file mode 100644 index 00000000..5734cd7c --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/cluster_delete_params.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["ClusterDeleteParams"] + + +class ClusterDeleteParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + all_floating_ips: bool + """ + Flag indicating whether the floating ips associated with server / cluster are + deleted + """ + + all_reserved_fixed_ips: bool + """ + Flag indicating whether the reserved fixed ips associated with server / cluster + are deleted + """ + + all_volumes: bool + """Flag indicating whether all attached volumes are deleted""" + + floating_ip_ids: SequenceNotStr[str] + """Optional list of floating ips to be deleted""" + + reserved_fixed_ip_ids: SequenceNotStr[str] + """Optional list of reserved fixed ips to be deleted""" + + volume_ids: SequenceNotStr[str] + """Optional list of volumes to be deleted""" diff --git a/src/gcore/types/cloud/gpu_virtual/cluster_list_params.py b/src/gcore/types/cloud/gpu_virtual/cluster_list_params.py new file mode 100644 index 00000000..e62cf44f --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/cluster_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ClusterListParams"] + + +class ClusterListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + limit: int + """Limit of items on a single page""" + + offset: int + """Offset in results list""" diff --git a/src/gcore/types/cloud/gpu_virtual/cluster_update_params.py b/src/gcore/types/cloud/gpu_virtual/cluster_update_params.py new file mode 100644 index 00000000..8ce9c924 --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/cluster_update_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ClusterUpdateParams"] + + +class ClusterUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: Required[str] + """Cluster name""" diff --git a/src/gcore/types/cloud/gpu_virtual/clusters/__init__.py b/src/gcore/types/cloud/gpu_virtual/clusters/__init__.py new file mode 100644 index 00000000..df222501 --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/clusters/__init__.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .flavor_list_params import FlavorListParams as FlavorListParams +from .gpu_virtual_flavor import GPUVirtualFlavor as GPUVirtualFlavor +from .server_list_params import ServerListParams as ServerListParams +from .image_upload_params import ImageUploadParams as ImageUploadParams +from .server_delete_params import ServerDeleteParams as ServerDeleteParams +from .gpu_virtual_interface import GPUVirtualInterface as GPUVirtualInterface +from .gpu_virtual_flavor_list import GPUVirtualFlavorList as GPUVirtualFlavorList +from .gpu_virtual_cluster_server import GPUVirtualClusterServer as GPUVirtualClusterServer +from .gpu_virtual_cluster_volume import GPUVirtualClusterVolume as GPUVirtualClusterVolume +from .gpu_virtual_interface_list import GPUVirtualInterfaceList as GPUVirtualInterfaceList +from .gpu_virtual_cluster_server_list import GPUVirtualClusterServerList as GPUVirtualClusterServerList +from .gpu_virtual_cluster_volume_list import GPUVirtualClusterVolumeList as GPUVirtualClusterVolumeList diff --git a/src/gcore/types/cloud/gpu_virtual/clusters/flavor_list_params.py b/src/gcore/types/cloud/gpu_virtual/clusters/flavor_list_params.py new file mode 100644 index 00000000..febeb592 --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/clusters/flavor_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["FlavorListParams"] + + +class FlavorListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + hide_disabled: bool + """Set to `true` to remove the disabled flavors from the response.""" + + include_prices: bool + """Set to `true` if the response should include flavor prices.""" diff --git a/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_cluster_server.py b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_cluster_server.py new file mode 100644 index 00000000..d8126e53 --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_cluster_server.py @@ -0,0 +1,77 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ...tag import Tag +from ....._models import BaseModel + +__all__ = ["GPUVirtualClusterServer", "SecurityGroup"] + + +class SecurityGroup(BaseModel): + id: str + """Security group ID""" + + name: str + """Security group name""" + + +class GPUVirtualClusterServer(BaseModel): + id: str + """Server unique identifier""" + + created_at: datetime + """Server creation date and time""" + + flavor: str + """Unique flavor identifier""" + + image_id: Optional[str] = None + """Server's image UUID""" + + ip_addresses: List[str] + """List of IP addresses""" + + name: str + """Server's name generated using cluster's name""" + + security_groups: List[SecurityGroup] + """Security groups""" + + ssh_key_name: Optional[str] = None + """SSH key pair assigned to the server""" + + status: Literal[ + "ACTIVE", + "BUILD", + "DELETED", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PASSWORD", + "PAUSED", + "REBOOT", + "REBUILD", + "RESCUE", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "UNKNOWN", + "VERIFY_RESIZE", + ] + """Current server status""" + + tags: List[Tag] + """User defined tags""" + + task_id: Optional[str] = None + """Identifier of the task currently modifying the GPU cluster""" + + updated_at: datetime + """Server update date and time""" diff --git a/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_cluster_server_list.py b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_cluster_server_list.py new file mode 100644 index 00000000..4d6f87a2 --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_cluster_server_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ....._models import BaseModel +from .gpu_virtual_cluster_server import GPUVirtualClusterServer + +__all__ = ["GPUVirtualClusterServerList"] + + +class GPUVirtualClusterServerList(BaseModel): + count: int + """Number of objects""" + + results: List[GPUVirtualClusterServer] + """Objects""" diff --git a/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_cluster_volume.py b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_cluster_volume.py new file mode 100644 index 00000000..bab71b55 --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_cluster_volume.py @@ -0,0 +1,64 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from datetime import datetime +from typing_extensions import Literal + +from ...tag import Tag +from ....._models import BaseModel + +__all__ = ["GPUVirtualClusterVolume"] + + +class GPUVirtualClusterVolume(BaseModel): + id: str + """Volume unique identifier""" + + bootable: bool + """True if this is bootable volume""" + + created_at: datetime + """Volume creation date and time""" + + name: str + """User defined name""" + + root_fs: bool + """True if this volume contains root file system""" + + server_id: str + """Server UUID""" + + size: int + """Volume size in GiB""" + + status: Literal[ + "attaching", + "available", + "awaiting-transfer", + "backing-up", + "creating", + "deleting", + "detaching", + "downloading", + "error", + "error_backing-up", + "error_deleting", + "error_extending", + "error_restoring", + "extending", + "in-use", + "maintenance", + "reserved", + "restoring-backup", + "retyping", + "reverting", + "uploading", + ] + """Current volume status""" + + tags: List[Tag] + """User defined tags""" + + type: str + """Volume type""" diff --git a/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_cluster_volume_list.py b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_cluster_volume_list.py new file mode 100644 index 00000000..85b9ab5d --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_cluster_volume_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ....._models import BaseModel +from .gpu_virtual_cluster_volume import GPUVirtualClusterVolume + +__all__ = ["GPUVirtualClusterVolumeList"] + + +class GPUVirtualClusterVolumeList(BaseModel): + count: int + """Number of objects""" + + results: List[GPUVirtualClusterVolume] + """Objects""" diff --git a/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_flavor.py b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_flavor.py new file mode 100644 index 00000000..9acea9fb --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_flavor.py @@ -0,0 +1,169 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal, TypeAlias + +from ....._models import BaseModel + +__all__ = [ + "GPUVirtualFlavor", + "GPUVirtualFlavorSerializerWithoutPrice", + "GPUVirtualFlavorSerializerWithoutPriceHardwareDescription", + "GPUVirtualFlavorSerializerWithoutPriceHardwareProperties", + "GPUVirtualFlavorSerializerWithoutPriceSupportedFeatures", + "GPUVirtualFlavorSerializerWithPrices", + "GPUVirtualFlavorSerializerWithPricesHardwareDescription", + "GPUVirtualFlavorSerializerWithPricesHardwareProperties", + "GPUVirtualFlavorSerializerWithPricesPrice", + "GPUVirtualFlavorSerializerWithPricesSupportedFeatures", +] + + +class GPUVirtualFlavorSerializerWithoutPriceHardwareDescription(BaseModel): + """Additional virtual hardware description""" + + gpu: Optional[str] = None + """Human-readable GPU description""" + + local_storage: Optional[int] = None + """Local storage capacity in GiB""" + + ram: Optional[int] = None + """RAM size in MiB""" + + vcpus: Optional[int] = None + """Virtual CPU count""" + + +class GPUVirtualFlavorSerializerWithoutPriceHardwareProperties(BaseModel): + """Additional virtual hardware properties""" + + gpu_count: Optional[int] = None + """The total count of available GPUs.""" + + gpu_manufacturer: Optional[str] = None + """The manufacturer of the graphics processing GPU""" + + gpu_model: Optional[str] = None + """GPU model""" + + nic_eth: Optional[str] = None + """The configuration of the Ethernet ports""" + + nic_ib: Optional[str] = None + """The configuration of the InfiniBand ports""" + + +class GPUVirtualFlavorSerializerWithoutPriceSupportedFeatures(BaseModel): + """Set of enabled features based on the flavor's type and configuration""" + + security_groups: bool + + +class GPUVirtualFlavorSerializerWithoutPrice(BaseModel): + architecture: Optional[str] = None + """Flavor architecture type""" + + capacity: int + """Number of available instances of given flavor""" + + disabled: bool + """If the flavor is disabled, new resources cannot be created using this flavor.""" + + hardware_description: GPUVirtualFlavorSerializerWithoutPriceHardwareDescription + """Additional virtual hardware description""" + + hardware_properties: GPUVirtualFlavorSerializerWithoutPriceHardwareProperties + """Additional virtual hardware properties""" + + name: str + """Flavor name""" + + supported_features: GPUVirtualFlavorSerializerWithoutPriceSupportedFeatures + """Set of enabled features based on the flavor's type and configuration""" + + +class GPUVirtualFlavorSerializerWithPricesHardwareDescription(BaseModel): + """Additional virtual hardware description""" + + gpu: Optional[str] = None + """Human-readable GPU description""" + + local_storage: Optional[int] = None + """Local storage capacity in GiB""" + + ram: Optional[int] = None + """RAM size in MiB""" + + vcpus: Optional[int] = None + """Virtual CPU count""" + + +class GPUVirtualFlavorSerializerWithPricesHardwareProperties(BaseModel): + """Additional virtual hardware properties""" + + gpu_count: Optional[int] = None + """The total count of available GPUs.""" + + gpu_manufacturer: Optional[str] = None + """The manufacturer of the graphics processing GPU""" + + gpu_model: Optional[str] = None + """GPU model""" + + nic_eth: Optional[str] = None + """The configuration of the Ethernet ports""" + + nic_ib: Optional[str] = None + """The configuration of the InfiniBand ports""" + + +class GPUVirtualFlavorSerializerWithPricesPrice(BaseModel): + """Flavor price.""" + + currency_code: Optional[str] = None + """Currency code. Shown if the `include_prices` query parameter if set to true""" + + price_per_hour: Optional[float] = None + """Price per hour. Shown if the `include_prices` query parameter if set to true""" + + price_per_month: Optional[float] = None + """Price per month. Shown if the `include_prices` query parameter if set to true""" + + price_status: Optional[Literal["error", "hide", "show"]] = None + """Price status for the UI""" + + +class GPUVirtualFlavorSerializerWithPricesSupportedFeatures(BaseModel): + """Set of enabled features based on the flavor's type and configuration""" + + security_groups: bool + + +class GPUVirtualFlavorSerializerWithPrices(BaseModel): + architecture: Optional[str] = None + """Flavor architecture type""" + + capacity: int + """Number of available instances of given flavor""" + + disabled: bool + """If the flavor is disabled, new resources cannot be created using this flavor.""" + + hardware_description: GPUVirtualFlavorSerializerWithPricesHardwareDescription + """Additional virtual hardware description""" + + hardware_properties: GPUVirtualFlavorSerializerWithPricesHardwareProperties + """Additional virtual hardware properties""" + + name: str + """Flavor name""" + + price: GPUVirtualFlavorSerializerWithPricesPrice + """Flavor price.""" + + supported_features: GPUVirtualFlavorSerializerWithPricesSupportedFeatures + """Set of enabled features based on the flavor's type and configuration""" + + +GPUVirtualFlavor: TypeAlias = Union[GPUVirtualFlavorSerializerWithoutPrice, GPUVirtualFlavorSerializerWithPrices] diff --git a/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_flavor_list.py b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_flavor_list.py new file mode 100644 index 00000000..71caf1fc --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_flavor_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ....._models import BaseModel +from .gpu_virtual_flavor import GPUVirtualFlavor + +__all__ = ["GPUVirtualFlavorList"] + + +class GPUVirtualFlavorList(BaseModel): + count: int + """Number of objects""" + + results: List[GPUVirtualFlavor] + """Objects""" diff --git a/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_interface.py b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_interface.py new file mode 100644 index 00000000..50473b10 --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_interface.py @@ -0,0 +1,192 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from ...tag import Tag +from ...route import Route +from ....._models import BaseModel +from ...ip_version import IPVersion +from ...floating_ip_status import FloatingIPStatus + +__all__ = ["GPUVirtualInterface", "FloatingIP", "IPAssignment", "Network", "NetworkSubnet"] + + +class FloatingIP(BaseModel): + id: str + """Floating IP ID""" + + created_at: datetime + """Datetime when the floating IP was created""" + + fixed_ip_address: Optional[str] = None + """IP address of the port the floating IP is attached to""" + + floating_ip_address: Optional[str] = None + """IP Address of the floating IP""" + + port_id: Optional[str] = None + """Port ID the floating IP is attached to. + + The `fixed_ip_address` is the IP address of the port. + """ + + router_id: Optional[str] = None + """Router ID""" + + status: Optional[FloatingIPStatus] = None + """Floating IP status""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + updated_at: datetime + """Datetime when the floating IP was last updated""" + + +class IPAssignment(BaseModel): + ip_address: str + """The IP address assigned to the port from the specified subnet""" + + subnet_id: str + """ID of the subnet that allocated the IP""" + + +class NetworkSubnet(BaseModel): + id: str + """Subnet id.""" + + available_ips: Optional[int] = None + """Number of available ips in subnet""" + + cidr: str + """CIDR""" + + created_at: datetime + """Datetime when the subnet was created""" + + dns_nameservers: Optional[List[str]] = None + """List IP addresses of a DNS resolver reachable from the network""" + + enable_dhcp: bool + """Indicates whether DHCP is enabled for this subnet. + + If true, IP addresses will be assigned automatically + """ + + gateway_ip: Optional[str] = None + """Default GW IPv4 address, advertised in DHCP routes of this subnet. + + If null, no gateway is advertised by this subnet. + """ + + has_router: bool + """Deprecated. Always returns `false`.""" + + host_routes: Optional[List[Route]] = None + """List of custom static routes to advertise via DHCP.""" + + ip_version: IPVersion + """IP version used by the subnet (IPv4 or IPv6)""" + + name: str + """Subnet name""" + + network_id: str + """Network ID""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + total_ips: Optional[int] = None + """Total number of ips in subnet""" + + updated_at: datetime + """Datetime when the subnet was last updated""" + + +class Network(BaseModel): + """Body of the network this port is attached to""" + + id: str + """Network ID""" + + created_at: datetime + """Datetime when the network was created""" + + external: bool + """True if the network `router:external` attribute""" + + mtu: int + """MTU (maximum transmission unit)""" + + name: str + """Network name""" + + port_security_enabled: bool + """ + Indicates `port_security_enabled` status of all newly created in the network + ports. + """ + + segmentation_id: Optional[int] = None + """Id of network segment""" + + shared: bool + """True when the network is shared with your project by external owner""" + + subnets: Optional[List[NetworkSubnet]] = None + """List of subnetworks""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + type: str + """Network type (vlan, vxlan)""" + + updated_at: datetime + """Datetime when the network was last updated""" + + +class GPUVirtualInterface(BaseModel): + floating_ips: List[FloatingIP] + """Bodies of floatingips that are NAT-ing ips of this port""" + + ip_assignments: List[IPAssignment] + """IP addresses assigned to this port""" + + mac_address: Optional[str] = None + """MAC address of the virtual port""" + + network: Network + """Body of the network this port is attached to""" + + network_id: str + """ID of the network the port is attached to""" + + port_id: str + """ID of virtual ethernet port object""" + + port_security_enabled: bool + """Port security status""" diff --git a/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_interface_list.py b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_interface_list.py new file mode 100644 index 00000000..006974ba --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/clusters/gpu_virtual_interface_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ....._models import BaseModel +from .gpu_virtual_interface import GPUVirtualInterface + +__all__ = ["GPUVirtualInterfaceList"] + + +class GPUVirtualInterfaceList(BaseModel): + count: int + """Number of objects""" + + results: List[GPUVirtualInterface] + """Objects""" diff --git a/src/gcore/types/cloud/gpu_virtual/clusters/image_upload_params.py b/src/gcore/types/cloud/gpu_virtual/clusters/image_upload_params.py new file mode 100644 index 00000000..269dfd76 --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/clusters/image_upload_params.py @@ -0,0 +1,56 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ImageUploadParams"] + + +class ImageUploadParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: Required[str] + """Image name""" + + url: Required[str] + """Image URL""" + + architecture: Optional[Literal["aarch64", "x86_64"]] + """Image architecture type: aarch64, `x86_64`""" + + cow_format: bool + """ + When True, image cannot be deleted unless all volumes, created from it, are + deleted. + """ + + hw_firmware_type: Optional[Literal["bios", "uefi"]] + """Specifies the type of firmware with which to boot the guest.""" + + os_distro: Optional[str] + """OS Distribution, i.e. Debian, CentOS, Ubuntu, CoreOS etc.""" + + os_type: Optional[Literal["linux", "windows"]] + """The operating system installed on the image. Linux by default""" + + os_version: Optional[str] + """OS version, i.e. 19.04 (for Ubuntu) or 9.4 for Debian""" + + ssh_key: Literal["allow", "deny", "required"] + """Permission to use a ssh key in instances""" + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ diff --git a/src/gcore/types/cloud/gpu_virtual/clusters/server_delete_params.py b/src/gcore/types/cloud/gpu_virtual/clusters/server_delete_params.py new file mode 100644 index 00000000..a9b463f7 --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/clusters/server_delete_params.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = ["ServerDeleteParams"] + + +class ServerDeleteParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + cluster_id: Required[str] + """Cluster unique identifier""" + + all_floating_ips: bool + """ + Flag indicating whether the floating ips associated with server / cluster are + deleted + """ + + all_reserved_fixed_ips: bool + """ + Flag indicating whether the reserved fixed ips associated with server / cluster + are deleted + """ + + all_volumes: bool + """Flag indicating whether all attached volumes are deleted""" + + floating_ip_ids: SequenceNotStr[str] + """Optional list of floating ips to be deleted""" + + reserved_fixed_ip_ids: SequenceNotStr[str] + """Optional list of reserved fixed ips to be deleted""" + + volume_ids: SequenceNotStr[str] + """Optional list of volumes to be deleted""" diff --git a/src/gcore/types/cloud/gpu_virtual/clusters/server_list_params.py b/src/gcore/types/cloud/gpu_virtual/clusters/server_list_params.py new file mode 100644 index 00000000..89f4cb6d --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/clusters/server_list_params.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Literal, Annotated, TypedDict + +from ....._types import SequenceNotStr +from ....._utils import PropertyInfo + +__all__ = ["ServerListParams"] + + +class ServerListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + changed_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """ + Filters the results to include only servers whose last change timestamp is less + than the specified datetime. Format: ISO 8601. + """ + + changed_since: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """ + Filters the results to include only servers whose last change timestamp is + greater than or equal to the specified datetime. Format: ISO 8601. + """ + + ip_address: str + """Filter servers by ip address.""" + + limit: int + """Limit of items on a single page""" + + name: str + """Filter servers by name. + + You can provide a full or partial name, servers with matching names will be + returned. For example, entering 'test' will return all servers that contain + 'test' in their name. + """ + + offset: int + """Offset in results list""" + + order_by: Literal["created_at.asc", "created_at.desc", "status.asc", "status.desc"] + """Order field""" + + status: Literal[ + "ACTIVE", + "BUILD", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PAUSED", + "REBOOT", + "REBUILD", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "VERIFY_RESIZE", + ] + """Filters servers by status.""" + + uuids: SequenceNotStr[str] + """Filter servers by uuid.""" diff --git a/src/gcore/types/cloud/gpu_virtual/gpu_virtual_cluster.py b/src/gcore/types/cloud/gpu_virtual/gpu_virtual_cluster.py new file mode 100644 index 00000000..3561daea --- /dev/null +++ b/src/gcore/types/cloud/gpu_virtual/gpu_virtual_cluster.py @@ -0,0 +1,195 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from ..tag import Tag +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "GPUVirtualCluster", + "ServersSettings", + "ServersSettingsFileShare", + "ServersSettingsInterface", + "ServersSettingsInterfaceExternalInterfaceOutputSerializer", + "ServersSettingsInterfaceSubnetInterfaceOutputSerializer", + "ServersSettingsInterfaceSubnetInterfaceOutputSerializerFloatingIP", + "ServersSettingsInterfaceAnySubnetInterfaceOutputSerializer", + "ServersSettingsInterfaceAnySubnetInterfaceOutputSerializerFloatingIP", + "ServersSettingsSecurityGroup", + "ServersSettingsVolume", +] + + +class ServersSettingsFileShare(BaseModel): + id: str + """Unique identifier of the file share in UUID format.""" + + mount_path: str + """Absolute mount path inside the system where the file share will be mounted.""" + + +class ServersSettingsInterfaceExternalInterfaceOutputSerializer(BaseModel): + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6, or use dual stack.""" + + name: Optional[str] = None + """Interface name""" + + type: Literal["external"] + + +class ServersSettingsInterfaceSubnetInterfaceOutputSerializerFloatingIP(BaseModel): + """Floating IP config for this subnet attachment""" + + source: Literal["new"] + + +class ServersSettingsInterfaceSubnetInterfaceOutputSerializer(BaseModel): + floating_ip: Optional[ServersSettingsInterfaceSubnetInterfaceOutputSerializerFloatingIP] = None + """Floating IP config for this subnet attachment""" + + name: Optional[str] = None + """Interface name""" + + network_id: str + """Network ID the subnet belongs to. Port will be plugged in this network""" + + subnet_id: str + """Port is assigned an IP address from this subnet""" + + type: Literal["subnet"] + + +class ServersSettingsInterfaceAnySubnetInterfaceOutputSerializerFloatingIP(BaseModel): + """Floating IP config for this subnet attachment""" + + source: Literal["new"] + + +class ServersSettingsInterfaceAnySubnetInterfaceOutputSerializer(BaseModel): + floating_ip: Optional[ServersSettingsInterfaceAnySubnetInterfaceOutputSerializerFloatingIP] = None + """Floating IP config for this subnet attachment""" + + ip_address: Optional[str] = None + """Fixed IP address""" + + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6, or use dual stack""" + + name: Optional[str] = None + """Interface name""" + + network_id: str + """Network ID the subnet belongs to. Port will be plugged in this network""" + + type: Literal["any_subnet"] + + +ServersSettingsInterface: TypeAlias = Annotated[ + Union[ + ServersSettingsInterfaceExternalInterfaceOutputSerializer, + ServersSettingsInterfaceSubnetInterfaceOutputSerializer, + ServersSettingsInterfaceAnySubnetInterfaceOutputSerializer, + ], + PropertyInfo(discriminator="type"), +] + + +class ServersSettingsSecurityGroup(BaseModel): + id: str + """Security group ID""" + + name: str + """Security group name""" + + +class ServersSettingsVolume(BaseModel): + boot_index: Optional[int] = None + """Boot index of the volume""" + + delete_on_termination: bool + """Flag indicating whether the volume is deleted on instance termination""" + + image_id: Optional[str] = None + """Image ID for the volume""" + + name: str + """Volume name""" + + size: int + """Volume size in GiB""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + type: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] + """Volume type""" + + +class ServersSettings(BaseModel): + file_shares: List[ServersSettingsFileShare] + """List of file shares mounted across the cluster.""" + + interfaces: List[ServersSettingsInterface] + + security_groups: List[ServersSettingsSecurityGroup] + """Security groups""" + + ssh_key_name: Optional[str] = None + """SSH key name""" + + user_data: Optional[str] = None + """Optional custom user data""" + + volumes: List[ServersSettingsVolume] + """List of volumes""" + + +class GPUVirtualCluster(BaseModel): + id: str + """Cluster unique identifier""" + + created_at: datetime + """Cluster creation date time""" + + flavor: str + """Cluster flavor name""" + + name: str + """Cluster name""" + + servers_count: int + """Cluster servers count""" + + servers_ids: List[str] + """List of cluster nodes""" + + servers_settings: ServersSettings + + status: Literal[ + "active", "creating", "degraded", "deleting", "error", "new", "rebooting", "rebuilding", "resizing", "shutoff" + ] + """Cluster status""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + updated_at: Optional[datetime] = None + """Cluster update date time""" diff --git a/src/gcore/types/cloud/health_monitor.py b/src/gcore/types/cloud/health_monitor.py new file mode 100644 index 00000000..44b8ab67 --- /dev/null +++ b/src/gcore/types/cloud/health_monitor.py @@ -0,0 +1,58 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .http_method import HTTPMethod +from .provisioning_status import ProvisioningStatus +from .lb_health_monitor_type import LbHealthMonitorType +from .load_balancer_operating_status import LoadBalancerOperatingStatus + +__all__ = ["HealthMonitor"] + + +class HealthMonitor(BaseModel): + id: str + """Health monitor ID""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + delay: int + """The time, in seconds, between sending probes to members""" + + max_retries: int + """Number of successes before the member is switched to ONLINE state""" + + max_retries_down: int + """Number of failures before the member is switched to ERROR state""" + + operating_status: LoadBalancerOperatingStatus + """Health Monitor operating status""" + + provisioning_status: ProvisioningStatus + """Health monitor lifecycle status""" + + timeout: int + """The maximum time to connect. Must be less than the delay value""" + + type: LbHealthMonitorType + """Health monitor type. Once health monitor is created, cannot be changed.""" + + expected_codes: Optional[str] = None + """Expected HTTP response codes. + + Can be a single code or a range of codes. Can only be used together with `HTTP` + or `HTTPS` health monitor type. For example, + 200,202,300-302,401,403,404,500-504. If not specified, the default is 200. + """ + + http_method: Optional[HTTPMethod] = None + """HTTP method""" + + url_path: Optional[str] = None + """URL Path. Defaults to '/'""" diff --git a/src/gcore/types/cloud/health_monitor_status.py b/src/gcore/types/cloud/health_monitor_status.py new file mode 100644 index 00000000..49b172af --- /dev/null +++ b/src/gcore/types/cloud/health_monitor_status.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel +from .provisioning_status import ProvisioningStatus +from .lb_health_monitor_type import LbHealthMonitorType +from .load_balancer_operating_status import LoadBalancerOperatingStatus + +__all__ = ["HealthMonitorStatus"] + + +class HealthMonitorStatus(BaseModel): + id: str + """UUID of the entity""" + + operating_status: LoadBalancerOperatingStatus + """Operating status of the entity""" + + provisioning_status: ProvisioningStatus + """Provisioning status of the entity""" + + type: LbHealthMonitorType + """Type of the Health Monitor""" diff --git a/src/gcore/types/cloud/http_method.py b/src/gcore/types/cloud/http_method.py new file mode 100644 index 00000000..803934ff --- /dev/null +++ b/src/gcore/types/cloud/http_method.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["HTTPMethod"] + +HTTPMethod: TypeAlias = Literal["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"] diff --git a/src/gcore/types/cloud/image.py b/src/gcore/types/cloud/image.py new file mode 100644 index 00000000..901b0436 --- /dev/null +++ b/src/gcore/types/cloud/image.py @@ -0,0 +1,109 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from .tag import Tag +from ..._models import BaseModel + +__all__ = ["Image"] + + +class Image(BaseModel): + id: str + """Image ID""" + + created_at: datetime + """Datetime when the image was created""" + + disk_format: str + """Disk format""" + + min_disk: int + """Minimal boot volume required""" + + min_ram: int + """Minimal VM RAM required""" + + name: str + """Image display name""" + + os_distro: str + """OS Distribution, i.e. Debian, CentOS, Ubuntu, CoreOS etc.""" + + os_type: Literal["linux", "windows"] + """The operating system installed on the image.""" + + os_version: str + """OS version, i.e. 19.04 (for Ubuntu) or 9.4 for Debian""" + + project_id: int + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + size: int + """Image size in bytes""" + + status: str + """Image status, i.e. active""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + updated_at: datetime + """Datetime when the image was updated""" + + visibility: str + """Image visibility. Globally visible images are public""" + + architecture: Optional[Literal["aarch64", "x86_64"]] = None + """An image architecture type: aarch64, `x86_64`""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + description: Optional[str] = None + """Image description""" + + display_order: Optional[int] = None + + gpu_driver: Optional[str] = None + """Name of the GPU driver vendor""" + + gpu_driver_type: Optional[str] = None + """Type of the GPU driver""" + + gpu_driver_version: Optional[str] = None + """Version of the installed GPU driver""" + + hw_firmware_type: Optional[Literal["bios", "uefi"]] = None + """Specifies the type of firmware with which to boot the guest.""" + + hw_machine_type: Optional[Literal["pc", "q35"]] = None + """A virtual chipset type.""" + + is_baremetal: Optional[bool] = None + """Set to true if the image will be used by bare metal servers. Defaults to false.""" + + ssh_key: Optional[Literal["allow", "deny", "required"]] = None + """Whether the image supports SSH key or not""" + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ diff --git a/src/gcore/types/cloud/image_list.py b/src/gcore/types/cloud/image_list.py new file mode 100644 index 00000000..4a4981fc --- /dev/null +++ b/src/gcore/types/cloud/image_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from .image import Image +from ..._models import BaseModel + +__all__ = ["ImageList"] + + +class ImageList(BaseModel): + count: int + """Number of objects""" + + results: List[Image] + """Objects""" diff --git a/src/gcore/types/cloud/inference/__init__.py b/src/gcore/types/cloud/inference/__init__.py new file mode 100644 index 00000000..66a4d198 --- /dev/null +++ b/src/gcore/types/cloud/inference/__init__.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .probe import Probe as Probe +from .probe_exec import ProbeExec as ProbeExec +from .probe_config import ProbeConfig as ProbeConfig +from .probe_http_get import ProbeHTTPGet as ProbeHTTPGet +from .inference_flavor import InferenceFlavor as InferenceFlavor +from .inference_secret import InferenceSecret as InferenceSecret +from .probe_tcp_socket import ProbeTcpSocket as ProbeTcpSocket +from .inference_api_key import InferenceAPIKey as InferenceAPIKey +from .flavor_list_params import FlavorListParams as FlavorListParams +from .secret_list_params import SecretListParams as SecretListParams +from .api_key_list_params import APIKeyListParams as APIKeyListParams +from .inference_deployment import InferenceDeployment as InferenceDeployment +from .secret_create_params import SecretCreateParams as SecretCreateParams +from .api_key_create_params import APIKeyCreateParams as APIKeyCreateParams +from .api_key_update_params import APIKeyUpdateParams as APIKeyUpdateParams +from .secret_replace_params import SecretReplaceParams as SecretReplaceParams +from .deployment_list_params import DeploymentListParams as DeploymentListParams +from .deployment_create_params import DeploymentCreateParams as DeploymentCreateParams +from .deployment_update_params import DeploymentUpdateParams as DeploymentUpdateParams +from .inference_api_key_created import InferenceAPIKeyCreated as InferenceAPIKeyCreated +from .inference_deployment_api_key import InferenceDeploymentAPIKey as InferenceDeploymentAPIKey +from .inference_registry_credentials import InferenceRegistryCredentials as InferenceRegistryCredentials +from .registry_credential_list_params import RegistryCredentialListParams as RegistryCredentialListParams +from .registry_credential_create_params import RegistryCredentialCreateParams as RegistryCredentialCreateParams +from .registry_credential_replace_params import RegistryCredentialReplaceParams as RegistryCredentialReplaceParams diff --git a/src/gcore/types/cloud/inference/api_key_create_params.py b/src/gcore/types/cloud/inference/api_key_create_params.py new file mode 100644 index 00000000..5c5ae755 --- /dev/null +++ b/src/gcore/types/cloud/inference/api_key_create_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["APIKeyCreateParams"] + + +class APIKeyCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + name: Required[str] + """Name of the API Key.""" + + description: str + """Description of the API Key.""" + + expires_at: str + """Expiration date of the API Key in ISO 8601 format.""" diff --git a/src/gcore/types/cloud/inference/api_key_list_params.py b/src/gcore/types/cloud/inference/api_key_list_params.py new file mode 100644 index 00000000..b6cb60ab --- /dev/null +++ b/src/gcore/types/cloud/inference/api_key_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["APIKeyListParams"] + + +class APIKeyListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + limit: int + """Optional. Limit the number of returned items""" + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ diff --git a/src/gcore/types/cloud/inference/api_key_update_params.py b/src/gcore/types/cloud/inference/api_key_update_params.py new file mode 100644 index 00000000..409e858f --- /dev/null +++ b/src/gcore/types/cloud/inference/api_key_update_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +__all__ = ["APIKeyUpdateParams"] + + +class APIKeyUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + description: Optional[str] + """Description of the API Key.""" diff --git a/src/gcore/types/cloud/inference/applications/__init__.py b/src/gcore/types/cloud/inference/applications/__init__.py new file mode 100644 index 00000000..8f061c13 --- /dev/null +++ b/src/gcore/types/cloud/inference/applications/__init__.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .deployment_create_params import DeploymentCreateParams as DeploymentCreateParams +from .deployment_update_params import DeploymentUpdateParams as DeploymentUpdateParams +from .inference_application_template import InferenceApplicationTemplate as InferenceApplicationTemplate +from .inference_application_deployment import InferenceApplicationDeployment as InferenceApplicationDeployment +from .inference_application_template_list import InferenceApplicationTemplateList as InferenceApplicationTemplateList +from .inference_application_deployment_list import ( + InferenceApplicationDeploymentList as InferenceApplicationDeploymentList, +) diff --git a/src/gcore/types/cloud/inference/applications/deployment_create_params.py b/src/gcore/types/cloud/inference/applications/deployment_create_params.py new file mode 100644 index 00000000..fbcfdf5a --- /dev/null +++ b/src/gcore/types/cloud/inference/applications/deployment_create_params.py @@ -0,0 +1,70 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable +from typing_extensions import Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = [ + "DeploymentCreateParams", + "ComponentsConfiguration", + "ComponentsConfigurationScale", + "ComponentsConfigurationParameterOverrides", +] + + +class DeploymentCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + application_name: Required[str] + """Identifier of the application from the catalog""" + + components_configuration: Required[Dict[str, ComponentsConfiguration]] + """Mapping of component names to their configuration (e.g., `"model": {...}`)""" + + name: Required[str] + """Desired name for the new deployment""" + + regions: Required[Iterable[int]] + """Geographical regions where the deployment should be created""" + + api_keys: SequenceNotStr[str] + """List of API keys for the application""" + + +class ComponentsConfigurationScale(TypedDict, total=False): + """Scaling parameters of the component""" + + max: Required[int] + """Maximum number of replicas the container can be scaled up to""" + + min: Required[int] + """Minimum number of replicas the component can be scaled down to""" + + +class ComponentsConfigurationParameterOverrides(TypedDict, total=False): + value: Required[str] + """New value assigned to the overridden parameter""" + + +class ComponentsConfiguration(TypedDict, total=False): + exposed: Required[bool] + """ + Whether the component should be exposed via a public endpoint (e.g., for + external inference/API access). + """ + + flavor: Required[str] + """ + Specifies the compute configuration (e.g., CPU/GPU size) to be used for the + component. + """ + + scale: Required[ComponentsConfigurationScale] + """Scaling parameters of the component""" + + parameter_overrides: Dict[str, ComponentsConfigurationParameterOverrides] + """Map of parameter overrides for customization""" diff --git a/src/gcore/types/cloud/inference/applications/deployment_update_params.py b/src/gcore/types/cloud/inference/applications/deployment_update_params.py new file mode 100644 index 00000000..d5055d72 --- /dev/null +++ b/src/gcore/types/cloud/inference/applications/deployment_update_params.py @@ -0,0 +1,64 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable, Optional +from typing_extensions import Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = [ + "DeploymentUpdateParams", + "ComponentsConfiguration", + "ComponentsConfigurationParameterOverrides", + "ComponentsConfigurationScale", +] + + +class DeploymentUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + api_keys: SequenceNotStr[str] + """List of API keys for the application""" + + components_configuration: Dict[str, Optional[ComponentsConfiguration]] + """Mapping of component names to their configuration (e.g., `"model": {...}`)""" + + regions: Iterable[int] + """Geographical regions to be updated for the deployment""" + + +class ComponentsConfigurationParameterOverrides(TypedDict, total=False): + value: Required[str] + """New value assigned to the overridden parameter""" + + +class ComponentsConfigurationScale(TypedDict, total=False): + """Scaling parameters of the component""" + + max: int + """Maximum number of replicas the container can be scaled up to""" + + min: int + """Minimum number of replicas the component can be scaled down to""" + + +class ComponentsConfiguration(TypedDict, total=False): + exposed: bool + """ + Whether the component should be exposed via a public endpoint (e.g., for + external inference/API access). + """ + + flavor: str + """ + Specifies the compute configuration (e.g., CPU/GPU size) to be used for the + component. + """ + + parameter_overrides: Dict[str, Optional[ComponentsConfigurationParameterOverrides]] + """Map of parameter overrides for customization""" + + scale: ComponentsConfigurationScale + """Scaling parameters of the component""" diff --git a/src/gcore/types/cloud/inference/applications/inference_application_deployment.py b/src/gcore/types/cloud/inference/applications/inference_application_deployment.py new file mode 100644 index 00000000..d864dc33 --- /dev/null +++ b/src/gcore/types/cloud/inference/applications/inference_application_deployment.py @@ -0,0 +1,115 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = [ + "InferenceApplicationDeployment", + "ComponentsConfiguration", + "ComponentsConfigurationParameterOverrides", + "ComponentsConfigurationScale", + "Status", + "StatusComponentInferences", + "StatusExposeAddresses", + "StatusRegion", + "StatusRegionComponents", +] + + +class ComponentsConfigurationParameterOverrides(BaseModel): + value: str + """New value assigned to the overridden parameter""" + + +class ComponentsConfigurationScale(BaseModel): + """Scaling parameters of the component""" + + max: int + """Maximum number of replicas the container can be scaled up to""" + + min: int + """Minimum number of replicas the component can be scaled down to""" + + +class ComponentsConfiguration(BaseModel): + exposed: bool + """Indicates if the component will obtain a public address""" + + flavor: str + """Chosen flavor or variant of the component""" + + parameter_overrides: Dict[str, ComponentsConfigurationParameterOverrides] + """Map of parameter overrides for customization""" + + scale: ComponentsConfigurationScale + """Scaling parameters of the component""" + + +class StatusComponentInferences(BaseModel): + flavor: str + """Flavor of the inference""" + + name: str + """Name of the inference""" + + +class StatusExposeAddresses(BaseModel): + address: str + """Global access endpoint for the component""" + + +class StatusRegionComponents(BaseModel): + error: str + """Error message if the component is in an error state""" + + status: str + """Current state of the component in a specific region""" + + +class StatusRegion(BaseModel): + components: Dict[str, StatusRegionComponents] + """Mapping of component names to their status in the region""" + + region_id: int + """Region ID""" + + status: str + """Current state of the deployment in a specific region""" + + +class Status(BaseModel): + """Current state of the deployment across regions""" + + component_inferences: Dict[str, StatusComponentInferences] + """Map of components and their inferences""" + + consolidated_status: Literal["Active", "Failed", "PartiallyDeployed", "Unknown"] + """High-level summary of the deployment status across all regions""" + + expose_addresses: Dict[str, StatusExposeAddresses] + """Map of component keys to their global access endpoints""" + + regions: List[StatusRegion] + """Status details for each deployment region""" + + +class InferenceApplicationDeployment(BaseModel): + api_keys: List[str] + """List of API keys for the application""" + + application_name: str + """Identifier of the application template from the catalog""" + + components_configuration: Dict[str, ComponentsConfiguration] + """Mapping of component names to their configuration (e.g., `"model": {...}`)""" + + name: str + """Unique identifier of the deployment""" + + regions: List[int] + """Geographical regions where the deployment is active""" + + status: Status + """Current state of the deployment across regions""" diff --git a/src/gcore/types/cloud/inference/applications/inference_application_deployment_list.py b/src/gcore/types/cloud/inference/applications/inference_application_deployment_list.py new file mode 100644 index 00000000..dd9a5c74 --- /dev/null +++ b/src/gcore/types/cloud/inference/applications/inference_application_deployment_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ....._models import BaseModel +from .inference_application_deployment import InferenceApplicationDeployment + +__all__ = ["InferenceApplicationDeploymentList"] + + +class InferenceApplicationDeploymentList(BaseModel): + count: int + """Number of objects""" + + results: List[InferenceApplicationDeployment] + """Objects""" diff --git a/src/gcore/types/cloud/inference/applications/inference_application_template.py b/src/gcore/types/cloud/inference/applications/inference_application_template.py new file mode 100644 index 00000000..c69602e2 --- /dev/null +++ b/src/gcore/types/cloud/inference/applications/inference_application_template.py @@ -0,0 +1,94 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from ....._models import BaseModel + +__all__ = ["InferenceApplicationTemplate", "Components", "ComponentsParameters", "ComponentsSuitableFlavor"] + + +class ComponentsParameters(BaseModel): + default_value: str + """Default value assigned if not provided""" + + description: str + """Description of the parameter's purpose""" + + display_name: str + """User-friendly name of the parameter""" + + enum_values: Optional[List[str]] = None + """Allowed values when type is "enum" """ + + max_value: Optional[str] = None + """Maximum value (applies to integer and float types)""" + + min_value: Optional[str] = None + """Minimum value (applies to integer and float types)""" + + pattern: Optional[str] = None + """Regexp pattern when type is "string" """ + + required: bool + """Indicates is parameter mandatory""" + + type: Literal["enum", "float", "integer", "string"] + """Determines the type of the parameter""" + + +class ComponentsSuitableFlavor(BaseModel): + name: str + """Name of the flavor""" + + +class Components(BaseModel): + description: str + """Summary of the component's functionality""" + + display_name: str + """Human-readable name of the component""" + + exposable: bool + """ + Indicates whether this component can expose a public-facing endpoint (e.g., for + inference or API access). + """ + + license_url: str + """URL to the component's license information""" + + parameters: Dict[str, ComponentsParameters] + """Configurable parameters for the component""" + + readme: str + """Detailed documentation or usage instructions""" + + required: bool + """Specifies if the component is required for the application""" + + suitable_flavors: List[ComponentsSuitableFlavor] + """List of compatible flavors or configurations""" + + +class InferenceApplicationTemplate(BaseModel): + components: Dict[str, Components] + """Configurable components of the application""" + + cover_url: str + """URL to the application's cover image""" + + description: str + """Brief overview of the application""" + + display_name: str + """Human-readable name of the application""" + + name: str + """Unique application identifier in the catalog""" + + readme: str + """Detailed documentation or instructions""" + + tags: Dict[str, str] + """Categorization key-value pairs""" diff --git a/src/gcore/types/cloud/inference/applications/inference_application_template_list.py b/src/gcore/types/cloud/inference/applications/inference_application_template_list.py new file mode 100644 index 00000000..582dd0ed --- /dev/null +++ b/src/gcore/types/cloud/inference/applications/inference_application_template_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ....._models import BaseModel +from .inference_application_template import InferenceApplicationTemplate + +__all__ = ["InferenceApplicationTemplateList"] + + +class InferenceApplicationTemplateList(BaseModel): + count: int + """Number of objects""" + + results: List[InferenceApplicationTemplate] + """Objects""" diff --git a/src/gcore/types/cloud/inference/deployment_create_params.py b/src/gcore/types/cloud/inference/deployment_create_params.py new file mode 100644 index 00000000..98f624cf --- /dev/null +++ b/src/gcore/types/cloud/inference/deployment_create_params.py @@ -0,0 +1,501 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable, Optional +from typing_extensions import Required, Annotated, TypedDict + +from ...._types import SequenceNotStr +from ...._utils import PropertyInfo +from ..laas_index_retention_policy_param import LaasIndexRetentionPolicyParam + +__all__ = [ + "DeploymentCreateParams", + "Container", + "ContainerScale", + "ContainerScaleTriggers", + "ContainerScaleTriggersCPU", + "ContainerScaleTriggersGPUMemory", + "ContainerScaleTriggersGPUUtilization", + "ContainerScaleTriggersHTTP", + "ContainerScaleTriggersMemory", + "ContainerScaleTriggersSqs", + "IngressOpts", + "Logging", + "Probes", + "ProbesLivenessProbe", + "ProbesLivenessProbeProbe", + "ProbesLivenessProbeProbeExec", + "ProbesLivenessProbeProbeHTTPGet", + "ProbesLivenessProbeProbeTcpSocket", + "ProbesReadinessProbe", + "ProbesReadinessProbeProbe", + "ProbesReadinessProbeProbeExec", + "ProbesReadinessProbeProbeHTTPGet", + "ProbesReadinessProbeProbeTcpSocket", + "ProbesStartupProbe", + "ProbesStartupProbeProbe", + "ProbesStartupProbeProbeExec", + "ProbesStartupProbeProbeHTTPGet", + "ProbesStartupProbeProbeTcpSocket", +] + + +class DeploymentCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + containers: Required[Iterable[Container]] + """List of containers for the inference instance.""" + + flavor_name: Required[str] + """Flavor name for the inference instance.""" + + image: Required[str] + """Docker image for the inference instance. + + This field should contain the image name and tag in the format 'name:tag', e.g., + 'nginx:latest'. It defaults to Docker Hub as the image registry, but any + accessible Docker image URL can be specified. + """ + + listening_port: Required[int] + """Listening port for the inference instance.""" + + name: Required[str] + """Inference instance name.""" + + api_keys: SequenceNotStr[str] + """List of API keys for the inference instance. + + Multiple keys can be attached to one deployment.If `auth_enabled` and `api_keys` + are both specified, a ValidationError will be raised. + """ + + auth_enabled: bool + """Set to `true` to enable API key authentication for the inference instance. + + `"Authorization": "Bearer *****"` or `"X-Api-Key": "*****"` header is required + for the requests to the instance if enabled. This field is deprecated and will + be removed in the future. Use `api_keys` field instead.If `auth_enabled` and + `api_keys` are both specified, a ValidationError will be raised. + """ + + command: Optional[SequenceNotStr[str]] + """Command to be executed when running a container from an image.""" + + credentials_name: Optional[str] + """Registry credentials name""" + + description: Optional[str] + """Inference instance description.""" + + envs: Dict[str, str] + """Environment variables for the inference instance.""" + + ingress_opts: Optional[IngressOpts] + """Ingress options for the inference instance""" + + logging: Optional[Logging] + """Logging configuration for the inference instance""" + + probes: Optional[Probes] + """Probes configured for all containers of the inference instance. + + If probes are not provided, and the `image_name` is from a the Model Catalog + registry, the default probes will be used. + """ + + api_timeout: Annotated[Optional[int], PropertyInfo(alias="timeout")] + """ + Specifies the duration in seconds without any requests after which the + containers will be downscaled to their minimum scale value as defined by + `scale.min`. If set, this helps in optimizing resource usage by reducing the + number of container instances during periods of inactivity. The default value + when the parameter is not set is 120. + """ + + +class ContainerScaleTriggersCPU(TypedDict, total=False): + """CPU trigger configuration""" + + threshold: Required[int] + """Threshold value for the trigger in percentage""" + + +class ContainerScaleTriggersGPUMemory(TypedDict, total=False): + """GPU memory trigger configuration. + + Calculated by `DCGM_FI_DEV_MEM_COPY_UTIL` metric + """ + + threshold: Required[int] + """Threshold value for the trigger in percentage""" + + +class ContainerScaleTriggersGPUUtilization(TypedDict, total=False): + """GPU utilization trigger configuration. + + Calculated by `DCGM_FI_DEV_GPU_UTIL` metric + """ + + threshold: Required[int] + """Threshold value for the trigger in percentage""" + + +class ContainerScaleTriggersHTTP(TypedDict, total=False): + """HTTP trigger configuration""" + + rate: Required[int] + """Request count per 'window' seconds for the http trigger""" + + window: Required[int] + """Time window for rate calculation in seconds""" + + +class ContainerScaleTriggersMemory(TypedDict, total=False): + """Memory trigger configuration""" + + threshold: Required[int] + """Threshold value for the trigger in percentage""" + + +class ContainerScaleTriggersSqs(TypedDict, total=False): + """SQS trigger configuration""" + + activation_queue_length: Required[int] + """Number of messages for activation""" + + aws_region: Required[str] + """AWS region""" + + queue_length: Required[int] + """Number of messages for one replica""" + + queue_url: Required[str] + """SQS queue URL""" + + secret_name: Required[str] + """Auth secret name""" + + aws_endpoint: Optional[str] + """Custom AWS endpoint""" + + scale_on_delayed: bool + """Scale on delayed messages""" + + scale_on_flight: bool + """Scale on in-flight messages""" + + +class ContainerScaleTriggers(TypedDict, total=False): + """Triggers for scaling actions""" + + cpu: Optional[ContainerScaleTriggersCPU] + """CPU trigger configuration""" + + gpu_memory: Optional[ContainerScaleTriggersGPUMemory] + """GPU memory trigger configuration. + + Calculated by `DCGM_FI_DEV_MEM_COPY_UTIL` metric + """ + + gpu_utilization: Optional[ContainerScaleTriggersGPUUtilization] + """GPU utilization trigger configuration. + + Calculated by `DCGM_FI_DEV_GPU_UTIL` metric + """ + + http: Optional[ContainerScaleTriggersHTTP] + """HTTP trigger configuration""" + + memory: Optional[ContainerScaleTriggersMemory] + """Memory trigger configuration""" + + sqs: Optional[ContainerScaleTriggersSqs] + """SQS trigger configuration""" + + +class ContainerScale(TypedDict, total=False): + """Scale for the container""" + + max: Required[int] + """Maximum scale for the container""" + + min: Required[int] + """Minimum scale for the container""" + + cooldown_period: Optional[int] + """Cooldown period between scaling actions in seconds""" + + polling_interval: Optional[int] + """Polling interval for scaling triggers in seconds""" + + triggers: ContainerScaleTriggers + """Triggers for scaling actions""" + + +class Container(TypedDict, total=False): + region_id: Required[int] + """Region id for the container""" + + scale: Required[ContainerScale] + """Scale for the container""" + + +class IngressOpts(TypedDict, total=False): + """Ingress options for the inference instance""" + + disable_response_buffering: bool + """Disable response buffering if true. + + A client usually has a much slower connection and can not consume the response + data as fast as it is produced by an upstream application. Ingress tries to + buffer the whole response in order to release the upstream application as soon + as possible.By default, the response buffering is enabled. + """ + + +class Logging(TypedDict, total=False): + """Logging configuration for the inference instance""" + + destination_region_id: Optional[int] + """ID of the region in which the logs will be stored""" + + enabled: bool + """Enable or disable log streaming""" + + retention_policy: Optional[LaasIndexRetentionPolicyParam] + """Logs retention policy""" + + topic_name: Optional[str] + """The topic name to stream logs to""" + + +class ProbesLivenessProbeProbeExec(TypedDict, total=False): + """Exec probe configuration""" + + command: Required[SequenceNotStr[str]] + """Command to be executed inside the running container.""" + + +class ProbesLivenessProbeProbeHTTPGet(TypedDict, total=False): + """HTTP GET probe configuration""" + + port: Required[int] + """Port number the probe should connect to.""" + + headers: Dict[str, str] + """HTTP headers to be sent with the request.""" + + host: Optional[str] + """Host name to send HTTP request to.""" + + path: str + """The endpoint to send the HTTP request to.""" + + schema: str + """Schema to use for the HTTP request.""" + + +class ProbesLivenessProbeProbeTcpSocket(TypedDict, total=False): + """TCP socket probe configuration""" + + port: Required[int] + """Port number to check if it's open.""" + + +class ProbesLivenessProbeProbe(TypedDict, total=False): + """Probe configuration (exec, `http_get` or `tcp_socket`)""" + + exec: Optional[ProbesLivenessProbeProbeExec] + """Exec probe configuration""" + + failure_threshold: int + """The number of consecutive probe failures that mark the container as unhealthy.""" + + http_get: Optional[ProbesLivenessProbeProbeHTTPGet] + """HTTP GET probe configuration""" + + initial_delay_seconds: int + """The initial delay before starting the first probe.""" + + period_seconds: int + """How often (in seconds) to perform the probe.""" + + success_threshold: int + """The number of consecutive successful probes that mark the container as healthy.""" + + tcp_socket: Optional[ProbesLivenessProbeProbeTcpSocket] + """TCP socket probe configuration""" + + timeout_seconds: int + """The timeout for each probe.""" + + +class ProbesLivenessProbe(TypedDict, total=False): + """Liveness probe configuration""" + + enabled: Required[bool] + """Whether the probe is enabled or not.""" + + probe: ProbesLivenessProbeProbe + """Probe configuration (exec, `http_get` or `tcp_socket`)""" + + +class ProbesReadinessProbeProbeExec(TypedDict, total=False): + """Exec probe configuration""" + + command: Required[SequenceNotStr[str]] + """Command to be executed inside the running container.""" + + +class ProbesReadinessProbeProbeHTTPGet(TypedDict, total=False): + """HTTP GET probe configuration""" + + port: Required[int] + """Port number the probe should connect to.""" + + headers: Dict[str, str] + """HTTP headers to be sent with the request.""" + + host: Optional[str] + """Host name to send HTTP request to.""" + + path: str + """The endpoint to send the HTTP request to.""" + + schema: str + """Schema to use for the HTTP request.""" + + +class ProbesReadinessProbeProbeTcpSocket(TypedDict, total=False): + """TCP socket probe configuration""" + + port: Required[int] + """Port number to check if it's open.""" + + +class ProbesReadinessProbeProbe(TypedDict, total=False): + """Probe configuration (exec, `http_get` or `tcp_socket`)""" + + exec: Optional[ProbesReadinessProbeProbeExec] + """Exec probe configuration""" + + failure_threshold: int + """The number of consecutive probe failures that mark the container as unhealthy.""" + + http_get: Optional[ProbesReadinessProbeProbeHTTPGet] + """HTTP GET probe configuration""" + + initial_delay_seconds: int + """The initial delay before starting the first probe.""" + + period_seconds: int + """How often (in seconds) to perform the probe.""" + + success_threshold: int + """The number of consecutive successful probes that mark the container as healthy.""" + + tcp_socket: Optional[ProbesReadinessProbeProbeTcpSocket] + """TCP socket probe configuration""" + + timeout_seconds: int + """The timeout for each probe.""" + + +class ProbesReadinessProbe(TypedDict, total=False): + """Readiness probe configuration""" + + enabled: Required[bool] + """Whether the probe is enabled or not.""" + + probe: ProbesReadinessProbeProbe + """Probe configuration (exec, `http_get` or `tcp_socket`)""" + + +class ProbesStartupProbeProbeExec(TypedDict, total=False): + """Exec probe configuration""" + + command: Required[SequenceNotStr[str]] + """Command to be executed inside the running container.""" + + +class ProbesStartupProbeProbeHTTPGet(TypedDict, total=False): + """HTTP GET probe configuration""" + + port: Required[int] + """Port number the probe should connect to.""" + + headers: Dict[str, str] + """HTTP headers to be sent with the request.""" + + host: Optional[str] + """Host name to send HTTP request to.""" + + path: str + """The endpoint to send the HTTP request to.""" + + schema: str + """Schema to use for the HTTP request.""" + + +class ProbesStartupProbeProbeTcpSocket(TypedDict, total=False): + """TCP socket probe configuration""" + + port: Required[int] + """Port number to check if it's open.""" + + +class ProbesStartupProbeProbe(TypedDict, total=False): + """Probe configuration (exec, `http_get` or `tcp_socket`)""" + + exec: Optional[ProbesStartupProbeProbeExec] + """Exec probe configuration""" + + failure_threshold: int + """The number of consecutive probe failures that mark the container as unhealthy.""" + + http_get: Optional[ProbesStartupProbeProbeHTTPGet] + """HTTP GET probe configuration""" + + initial_delay_seconds: int + """The initial delay before starting the first probe.""" + + period_seconds: int + """How often (in seconds) to perform the probe.""" + + success_threshold: int + """The number of consecutive successful probes that mark the container as healthy.""" + + tcp_socket: Optional[ProbesStartupProbeProbeTcpSocket] + """TCP socket probe configuration""" + + timeout_seconds: int + """The timeout for each probe.""" + + +class ProbesStartupProbe(TypedDict, total=False): + """Startup probe configuration""" + + enabled: Required[bool] + """Whether the probe is enabled or not.""" + + probe: ProbesStartupProbeProbe + """Probe configuration (exec, `http_get` or `tcp_socket`)""" + + +class Probes(TypedDict, total=False): + """Probes configured for all containers of the inference instance. + + If probes are not provided, and the `image_name` is from a the Model Catalog registry, the default probes will be used. + """ + + liveness_probe: Optional[ProbesLivenessProbe] + """Liveness probe configuration""" + + readiness_probe: Optional[ProbesReadinessProbe] + """Readiness probe configuration""" + + startup_probe: Optional[ProbesStartupProbe] + """Startup probe configuration""" diff --git a/src/gcore/types/cloud/inference/deployment_list_params.py b/src/gcore/types/cloud/inference/deployment_list_params.py new file mode 100644 index 00000000..74410be1 --- /dev/null +++ b/src/gcore/types/cloud/inference/deployment_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["DeploymentListParams"] + + +class DeploymentListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + limit: int + """Optional. Limit the number of returned items""" + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ diff --git a/src/gcore/types/cloud/inference/deployment_update_params.py b/src/gcore/types/cloud/inference/deployment_update_params.py new file mode 100644 index 00000000..ad86e3eb --- /dev/null +++ b/src/gcore/types/cloud/inference/deployment_update_params.py @@ -0,0 +1,492 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable, Optional +from typing_extensions import Required, Annotated, TypedDict + +from ...._types import SequenceNotStr +from ...._utils import PropertyInfo +from ..laas_index_retention_policy_param import LaasIndexRetentionPolicyParam + +__all__ = [ + "DeploymentUpdateParams", + "Container", + "ContainerScale", + "ContainerScaleTriggers", + "ContainerScaleTriggersCPU", + "ContainerScaleTriggersGPUMemory", + "ContainerScaleTriggersGPUUtilization", + "ContainerScaleTriggersHTTP", + "ContainerScaleTriggersMemory", + "ContainerScaleTriggersSqs", + "IngressOpts", + "Logging", + "Probes", + "ProbesLivenessProbe", + "ProbesLivenessProbeProbe", + "ProbesLivenessProbeProbeExec", + "ProbesLivenessProbeProbeHTTPGet", + "ProbesLivenessProbeProbeTcpSocket", + "ProbesReadinessProbe", + "ProbesReadinessProbeProbe", + "ProbesReadinessProbeProbeExec", + "ProbesReadinessProbeProbeHTTPGet", + "ProbesReadinessProbeProbeTcpSocket", + "ProbesStartupProbe", + "ProbesStartupProbeProbe", + "ProbesStartupProbeProbeExec", + "ProbesStartupProbeProbeHTTPGet", + "ProbesStartupProbeProbeTcpSocket", +] + + +class DeploymentUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + api_keys: Optional[SequenceNotStr[str]] + """List of API keys for the inference instance. + + Multiple keys can be attached to one deployment.If `auth_enabled` and `api_keys` + are both specified, a ValidationError will be raised.If `[]` is provided, the + API keys will be removed and auth will be disabled on the deployment. + """ + + auth_enabled: bool + """Set to `true` to enable API key authentication for the inference instance. + + `"Authorization": "Bearer *****"` or `"X-Api-Key": "*****"` header is required + for the requests to the instance if enabled. This field is deprecated and will + be removed in the future. Use `api_keys` field instead.If `auth_enabled` and + `api_keys` are both specified, a ValidationError will be raised. + """ + + command: Optional[SequenceNotStr[str]] + """Command to be executed when running a container from an image.""" + + containers: Optional[Iterable[Container]] + """List of containers for the inference instance.""" + + credentials_name: Optional[str] + """Registry credentials name""" + + description: Optional[str] + """Inference instance description.""" + + envs: Optional[Dict[str, str]] + """Environment variables for the inference instance.""" + + flavor_name: str + """Flavor name for the inference instance.""" + + image: Optional[str] + """Docker image for the inference instance. + + This field should contain the image name and tag in the format 'name:tag', e.g., + 'nginx:latest'. It defaults to Docker Hub as the image registry, but any + accessible Docker image URL can be specified. + """ + + ingress_opts: Optional[IngressOpts] + """Ingress options for the inference instance""" + + listening_port: Optional[int] + """Listening port for the inference instance.""" + + logging: Optional[Logging] + """Logging configuration for the inference instance""" + + probes: Optional[Probes] + """Probes configured for all containers of the inference instance.""" + + api_timeout: Annotated[Optional[int], PropertyInfo(alias="timeout")] + """ + Specifies the duration in seconds without any requests after which the + containers will be downscaled to their minimum scale value as defined by + `scale.min`. If set, this helps in optimizing resource usage by reducing the + number of container instances during periods of inactivity. The default value + when the parameter is not set is 120. + """ + + +class ContainerScaleTriggersCPU(TypedDict, total=False): + """CPU trigger configuration""" + + threshold: Required[int] + """Threshold value for the trigger in percentage""" + + +class ContainerScaleTriggersGPUMemory(TypedDict, total=False): + """GPU memory trigger configuration. + + Calculated by `DCGM_FI_DEV_MEM_COPY_UTIL` metric + """ + + threshold: Required[int] + """Threshold value for the trigger in percentage""" + + +class ContainerScaleTriggersGPUUtilization(TypedDict, total=False): + """GPU utilization trigger configuration. + + Calculated by `DCGM_FI_DEV_GPU_UTIL` metric + """ + + threshold: Required[int] + """Threshold value for the trigger in percentage""" + + +class ContainerScaleTriggersHTTP(TypedDict, total=False): + """HTTP trigger configuration""" + + rate: Required[int] + """Request count per 'window' seconds for the http trigger""" + + window: Required[int] + """Time window for rate calculation in seconds""" + + +class ContainerScaleTriggersMemory(TypedDict, total=False): + """Memory trigger configuration""" + + threshold: Required[int] + """Threshold value for the trigger in percentage""" + + +class ContainerScaleTriggersSqs(TypedDict, total=False): + """SQS trigger configuration""" + + activation_queue_length: Required[int] + """Number of messages for activation""" + + aws_region: Required[str] + """AWS region""" + + queue_length: Required[int] + """Number of messages for one replica""" + + queue_url: Required[str] + """SQS queue URL""" + + secret_name: Required[str] + """Auth secret name""" + + aws_endpoint: Optional[str] + """Custom AWS endpoint""" + + scale_on_delayed: bool + """Scale on delayed messages""" + + scale_on_flight: bool + """Scale on in-flight messages""" + + +class ContainerScaleTriggers(TypedDict, total=False): + """Triggers for scaling actions""" + + cpu: Optional[ContainerScaleTriggersCPU] + """CPU trigger configuration""" + + gpu_memory: Optional[ContainerScaleTriggersGPUMemory] + """GPU memory trigger configuration. + + Calculated by `DCGM_FI_DEV_MEM_COPY_UTIL` metric + """ + + gpu_utilization: Optional[ContainerScaleTriggersGPUUtilization] + """GPU utilization trigger configuration. + + Calculated by `DCGM_FI_DEV_GPU_UTIL` metric + """ + + http: Optional[ContainerScaleTriggersHTTP] + """HTTP trigger configuration""" + + memory: Optional[ContainerScaleTriggersMemory] + """Memory trigger configuration""" + + sqs: Optional[ContainerScaleTriggersSqs] + """SQS trigger configuration""" + + +class ContainerScale(TypedDict, total=False): + """Scale for the container""" + + max: Required[int] + """Maximum scale for the container""" + + min: Required[int] + """Minimum scale for the container""" + + cooldown_period: int + """Cooldown period between scaling actions in seconds""" + + polling_interval: int + """Polling interval for scaling triggers in seconds""" + + triggers: ContainerScaleTriggers + """Triggers for scaling actions""" + + +class Container(TypedDict, total=False): + region_id: Required[int] + """Region id for the container""" + + scale: Required[ContainerScale] + """Scale for the container""" + + +class IngressOpts(TypedDict, total=False): + """Ingress options for the inference instance""" + + disable_response_buffering: bool + """Disable response buffering if true. + + A client usually has a much slower connection and can not consume the response + data as fast as it is produced by an upstream application. Ingress tries to + buffer the whole response in order to release the upstream application as soon + as possible.By default, the response buffering is enabled. + """ + + +class Logging(TypedDict, total=False): + """Logging configuration for the inference instance""" + + destination_region_id: Optional[int] + """ID of the region in which the logs will be stored""" + + enabled: bool + """Enable or disable log streaming""" + + retention_policy: Optional[LaasIndexRetentionPolicyParam] + """Logs retention policy""" + + topic_name: Optional[str] + """The topic name to stream logs to""" + + +class ProbesLivenessProbeProbeExec(TypedDict, total=False): + """Exec probe configuration""" + + command: SequenceNotStr[str] + """Command to be executed inside the running container.""" + + +class ProbesLivenessProbeProbeHTTPGet(TypedDict, total=False): + """HTTP GET probe configuration""" + + headers: Dict[str, str] + """HTTP headers to be sent with the request.""" + + host: str + """Host name to send HTTP request to.""" + + path: str + """The endpoint to send the HTTP request to.""" + + port: int + """Port number the probe should connect to.""" + + schema: str + """Schema to use for the HTTP request.""" + + +class ProbesLivenessProbeProbeTcpSocket(TypedDict, total=False): + """TCP socket probe configuration""" + + port: int + """Port number to check if it's open.""" + + +class ProbesLivenessProbeProbe(TypedDict, total=False): + """Probe configuration (exec, `http_get` or `tcp_socket`)""" + + exec: Optional[ProbesLivenessProbeProbeExec] + """Exec probe configuration""" + + failure_threshold: int + """The number of consecutive probe failures that mark the container as unhealthy.""" + + http_get: Optional[ProbesLivenessProbeProbeHTTPGet] + """HTTP GET probe configuration""" + + initial_delay_seconds: int + """The initial delay before starting the first probe.""" + + period_seconds: int + """How often (in seconds) to perform the probe.""" + + success_threshold: int + """The number of consecutive successful probes that mark the container as healthy.""" + + tcp_socket: Optional[ProbesLivenessProbeProbeTcpSocket] + """TCP socket probe configuration""" + + timeout_seconds: int + """The timeout for each probe.""" + + +class ProbesLivenessProbe(TypedDict, total=False): + """Liveness probe configuration""" + + enabled: bool + """Whether the probe is enabled or not.""" + + probe: ProbesLivenessProbeProbe + """Probe configuration (exec, `http_get` or `tcp_socket`)""" + + +class ProbesReadinessProbeProbeExec(TypedDict, total=False): + """Exec probe configuration""" + + command: SequenceNotStr[str] + """Command to be executed inside the running container.""" + + +class ProbesReadinessProbeProbeHTTPGet(TypedDict, total=False): + """HTTP GET probe configuration""" + + headers: Dict[str, str] + """HTTP headers to be sent with the request.""" + + host: str + """Host name to send HTTP request to.""" + + path: str + """The endpoint to send the HTTP request to.""" + + port: int + """Port number the probe should connect to.""" + + schema: str + """Schema to use for the HTTP request.""" + + +class ProbesReadinessProbeProbeTcpSocket(TypedDict, total=False): + """TCP socket probe configuration""" + + port: int + """Port number to check if it's open.""" + + +class ProbesReadinessProbeProbe(TypedDict, total=False): + """Probe configuration (exec, `http_get` or `tcp_socket`)""" + + exec: Optional[ProbesReadinessProbeProbeExec] + """Exec probe configuration""" + + failure_threshold: int + """The number of consecutive probe failures that mark the container as unhealthy.""" + + http_get: Optional[ProbesReadinessProbeProbeHTTPGet] + """HTTP GET probe configuration""" + + initial_delay_seconds: int + """The initial delay before starting the first probe.""" + + period_seconds: int + """How often (in seconds) to perform the probe.""" + + success_threshold: int + """The number of consecutive successful probes that mark the container as healthy.""" + + tcp_socket: Optional[ProbesReadinessProbeProbeTcpSocket] + """TCP socket probe configuration""" + + timeout_seconds: int + """The timeout for each probe.""" + + +class ProbesReadinessProbe(TypedDict, total=False): + """Readiness probe configuration""" + + enabled: bool + """Whether the probe is enabled or not.""" + + probe: ProbesReadinessProbeProbe + """Probe configuration (exec, `http_get` or `tcp_socket`)""" + + +class ProbesStartupProbeProbeExec(TypedDict, total=False): + """Exec probe configuration""" + + command: SequenceNotStr[str] + """Command to be executed inside the running container.""" + + +class ProbesStartupProbeProbeHTTPGet(TypedDict, total=False): + """HTTP GET probe configuration""" + + headers: Dict[str, str] + """HTTP headers to be sent with the request.""" + + host: str + """Host name to send HTTP request to.""" + + path: str + """The endpoint to send the HTTP request to.""" + + port: int + """Port number the probe should connect to.""" + + schema: str + """Schema to use for the HTTP request.""" + + +class ProbesStartupProbeProbeTcpSocket(TypedDict, total=False): + """TCP socket probe configuration""" + + port: int + """Port number to check if it's open.""" + + +class ProbesStartupProbeProbe(TypedDict, total=False): + """Probe configuration (exec, `http_get` or `tcp_socket`)""" + + exec: Optional[ProbesStartupProbeProbeExec] + """Exec probe configuration""" + + failure_threshold: int + """The number of consecutive probe failures that mark the container as unhealthy.""" + + http_get: Optional[ProbesStartupProbeProbeHTTPGet] + """HTTP GET probe configuration""" + + initial_delay_seconds: int + """The initial delay before starting the first probe.""" + + period_seconds: int + """How often (in seconds) to perform the probe.""" + + success_threshold: int + """The number of consecutive successful probes that mark the container as healthy.""" + + tcp_socket: Optional[ProbesStartupProbeProbeTcpSocket] + """TCP socket probe configuration""" + + timeout_seconds: int + """The timeout for each probe.""" + + +class ProbesStartupProbe(TypedDict, total=False): + """Startup probe configuration""" + + enabled: bool + """Whether the probe is enabled or not.""" + + probe: ProbesStartupProbeProbe + """Probe configuration (exec, `http_get` or `tcp_socket`)""" + + +class Probes(TypedDict, total=False): + """Probes configured for all containers of the inference instance.""" + + liveness_probe: Optional[ProbesLivenessProbe] + """Liveness probe configuration""" + + readiness_probe: Optional[ProbesReadinessProbe] + """Readiness probe configuration""" + + startup_probe: Optional[ProbesStartupProbe] + """Startup probe configuration""" diff --git a/src/gcore/types/cloud/inference/deployments/__init__.py b/src/gcore/types/cloud/inference/deployments/__init__.py new file mode 100644 index 00000000..bbef5855 --- /dev/null +++ b/src/gcore/types/cloud/inference/deployments/__init__.py @@ -0,0 +1,6 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .log_list_params import LogListParams as LogListParams +from .inference_deployment_log import InferenceDeploymentLog as InferenceDeploymentLog diff --git a/src/gcore/types/cloud/inference/deployments/inference_deployment_log.py b/src/gcore/types/cloud/inference/deployments/inference_deployment_log.py new file mode 100644 index 00000000..1737bf1b --- /dev/null +++ b/src/gcore/types/cloud/inference/deployments/inference_deployment_log.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ....._models import BaseModel + +__all__ = ["InferenceDeploymentLog"] + + +class InferenceDeploymentLog(BaseModel): + message: str + """Log message.""" + + pod: str + """Pod name.""" + + region_id: int + """Region ID where the container is deployed.""" + + time: datetime + """Log message timestamp in ISO 8601 format.""" diff --git a/src/gcore/types/cloud/inference/deployments/log_list_params.py b/src/gcore/types/cloud/inference/deployments/log_list_params.py new file mode 100644 index 00000000..21d57ac2 --- /dev/null +++ b/src/gcore/types/cloud/inference/deployments/log_list_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["LogListParams"] + + +class LogListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + limit: int + """Optional. Limit the number of returned items""" + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ + + order_by: Literal["time.asc", "time.desc"] + """Order by field""" + + region_id: Optional[int] + """Region ID""" diff --git a/src/gcore/types/cloud/inference/flavor_list_params.py b/src/gcore/types/cloud/inference/flavor_list_params.py new file mode 100644 index 00000000..2ec6f0e0 --- /dev/null +++ b/src/gcore/types/cloud/inference/flavor_list_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["FlavorListParams"] + + +class FlavorListParams(TypedDict, total=False): + limit: int + """Optional. Limit the number of returned items""" + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ diff --git a/src/gcore/types/cloud/inference/inference_api_key.py b/src/gcore/types/cloud/inference/inference_api_key.py new file mode 100644 index 00000000..738cdfbe --- /dev/null +++ b/src/gcore/types/cloud/inference/inference_api_key.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ...._models import BaseModel + +__all__ = ["InferenceAPIKey"] + + +class InferenceAPIKey(BaseModel): + created_at: str + """Timestamp when the API Key was created.""" + + deployment_names: List[str] + """List of inference deployment names to which this API Key has been attached.""" + + description: Optional[str] = None + """Description of the API Key.""" + + expires_at: Optional[str] = None + """Timestamp when the API Key will expire.""" + + name: str + """API Key name.""" diff --git a/src/gcore/types/cloud/inference/inference_api_key_created.py b/src/gcore/types/cloud/inference/inference_api_key_created.py new file mode 100644 index 00000000..b479f800 --- /dev/null +++ b/src/gcore/types/cloud/inference/inference_api_key_created.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ...._models import BaseModel + +__all__ = ["InferenceAPIKeyCreated"] + + +class InferenceAPIKeyCreated(BaseModel): + created_at: str + """Timestamp when the API Key was created.""" + + deployment_names: List[str] + """List of inference deployment names to which this API Key has been attached.""" + + description: Optional[str] = None + """Description of the API Key.""" + + expires_at: Optional[str] = None + """Timestamp when the API Key will expire.""" + + name: str + """API Key name.""" + + secret: str + """The actual API Key secret.""" diff --git a/src/gcore/types/cloud/inference/inference_deployment.py b/src/gcore/types/cloud/inference/inference_deployment.py new file mode 100644 index 00000000..df5fe742 --- /dev/null +++ b/src/gcore/types/cloud/inference/inference_deployment.py @@ -0,0 +1,296 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from ..logging import Logging +from ...._models import BaseModel +from .probe_config import ProbeConfig + +__all__ = [ + "InferenceDeployment", + "Container", + "ContainerDeployStatus", + "ContainerScale", + "ContainerScaleTriggers", + "ContainerScaleTriggersCPU", + "ContainerScaleTriggersGPUMemory", + "ContainerScaleTriggersGPUUtilization", + "ContainerScaleTriggersHTTP", + "ContainerScaleTriggersMemory", + "ContainerScaleTriggersSqs", + "IngressOpts", + "ObjectReference", + "Probes", +] + + +class ContainerDeployStatus(BaseModel): + """Status of the containers deployment""" + + ready: int + """Number of ready instances""" + + total: int + """Total number of instances""" + + +class ContainerScaleTriggersCPU(BaseModel): + """CPU trigger configuration""" + + threshold: int + """Threshold value for the trigger in percentage""" + + +class ContainerScaleTriggersGPUMemory(BaseModel): + """GPU memory trigger configuration. + + Calculated by `DCGM_FI_DEV_MEM_COPY_UTIL` metric + """ + + threshold: int + """Threshold value for the trigger in percentage""" + + +class ContainerScaleTriggersGPUUtilization(BaseModel): + """GPU utilization trigger configuration. + + Calculated by `DCGM_FI_DEV_GPU_UTIL` metric + """ + + threshold: int + """Threshold value for the trigger in percentage""" + + +class ContainerScaleTriggersHTTP(BaseModel): + """HTTP trigger configuration""" + + rate: int + """Request count per 'window' seconds for the http trigger""" + + window: int + """Time window for rate calculation in seconds""" + + +class ContainerScaleTriggersMemory(BaseModel): + """Memory trigger configuration""" + + threshold: int + """Threshold value for the trigger in percentage""" + + +class ContainerScaleTriggersSqs(BaseModel): + """SQS trigger configuration""" + + activation_queue_length: int + """Number of messages for activation""" + + aws_endpoint: Optional[str] = None + """Custom AWS endpoint""" + + aws_region: str + """AWS region""" + + queue_length: int + """Number of messages for one replica""" + + queue_url: str + """SQS queue URL""" + + scale_on_delayed: bool + """Scale on delayed messages""" + + scale_on_flight: bool + """Scale on in-flight messages""" + + secret_name: str + """Auth secret name""" + + +class ContainerScaleTriggers(BaseModel): + """Triggers for scaling actions""" + + cpu: Optional[ContainerScaleTriggersCPU] = None + """CPU trigger configuration""" + + gpu_memory: Optional[ContainerScaleTriggersGPUMemory] = None + """GPU memory trigger configuration. + + Calculated by `DCGM_FI_DEV_MEM_COPY_UTIL` metric + """ + + gpu_utilization: Optional[ContainerScaleTriggersGPUUtilization] = None + """GPU utilization trigger configuration. + + Calculated by `DCGM_FI_DEV_GPU_UTIL` metric + """ + + http: Optional[ContainerScaleTriggersHTTP] = None + """HTTP trigger configuration""" + + memory: Optional[ContainerScaleTriggersMemory] = None + """Memory trigger configuration""" + + sqs: Optional[ContainerScaleTriggersSqs] = None + """SQS trigger configuration""" + + +class ContainerScale(BaseModel): + """Scale for the container""" + + cooldown_period: Optional[int] = None + """Cooldown period between scaling actions in seconds""" + + max: int + """Maximum scale for the container""" + + min: int + """Minimum scale for the container""" + + polling_interval: Optional[int] = None + """Polling interval for scaling triggers in seconds""" + + triggers: ContainerScaleTriggers + """Triggers for scaling actions""" + + +class Container(BaseModel): + address: Optional[str] = None + """Address of the inference instance""" + + deploy_status: ContainerDeployStatus + """Status of the containers deployment""" + + error_message: Optional[str] = None + """Error message if the container deployment failed""" + + region_id: int + """Region name for the container""" + + scale: ContainerScale + """Scale for the container""" + + +class IngressOpts(BaseModel): + """Ingress options for the inference instance""" + + disable_response_buffering: bool + """Disable response buffering if true. + + A client usually has a much slower connection and can not consume the response + data as fast as it is produced by an upstream application. Ingress tries to + buffer the whole response in order to release the upstream application as soon + as possible.By default, the response buffering is enabled. + """ + + +class ObjectReference(BaseModel): + kind: Literal["AppDeployment"] + """Kind of the inference object to be referenced""" + + name: str + """Name of the inference object to be referenced""" + + +class Probes(BaseModel): + """Probes configured for all containers of the inference instance.""" + + liveness_probe: Optional[ProbeConfig] = None + """Liveness probe configuration""" + + readiness_probe: Optional[ProbeConfig] = None + """Readiness probe configuration""" + + startup_probe: Optional[ProbeConfig] = None + """Startup probe configuration""" + + +class InferenceDeployment(BaseModel): + address: Optional[str] = None + """Address of the inference instance""" + + auth_enabled: bool + """`true` if instance uses API key authentication. + + `"Authorization": "Bearer *****"` or `"X-Api-Key": "*****"` header is required + for the requests to the instance if enabled. + """ + + command: Optional[str] = None + """Command to be executed when running a container from an image.""" + + containers: List[Container] + """List of containers for the inference instance""" + + created_at: Optional[str] = None + """Inference instance creation date in ISO 8601 format.""" + + credentials_name: str + """Registry credentials name""" + + description: str + """Inference instance description.""" + + envs: Optional[Dict[str, str]] = None + """Environment variables for the inference instance""" + + flavor_name: str + """Flavor name for the inference instance""" + + image: str + """Docker image for the inference instance. + + This field should contain the image name and tag in the format 'name:tag', e.g., + 'nginx:latest'. It defaults to Docker Hub as the image registry, but any + accessible Docker image URL can be specified. + """ + + ingress_opts: Optional[IngressOpts] = None + """Ingress options for the inference instance""" + + listening_port: int + """Listening port for the inference instance.""" + + logging: Optional[Logging] = None + """Logging configuration for the inference instance""" + + name: str + """Inference instance name.""" + + object_references: List[ObjectReference] + """Indicates to which parent object this inference belongs to.""" + + probes: Optional[Probes] = None + """Probes configured for all containers of the inference instance.""" + + project_id: int + """Project ID. If not provided, your default project ID will be used.""" + + status: Literal["ACTIVE", "DELETING", "DEPLOYING", "DISABLED", "PARTIALLYDEPLOYED", "PENDING"] + """Inference instance status. + + Value can be one of the following: + + - `DEPLOYING` - The instance is being deployed. Containers are not yet created. + - `PARTIALLYDEPLOYED` - All containers have been created, but some may not be + ready yet. Instances stuck in this state typically indicate either image being + pulled, or a failure of some kind. In the latter case, the `error_message` + field of the respective container object in the `containers` collection + explains the failure reason. + - `ACTIVE` - The instance is running and ready to accept requests. + - `DISABLED` - The instance is disabled and not accepting any requests. + - `PENDING` - The instance is running but scaled to zero. It will be + automatically scaled up when a request is made. + - `DELETING` - The instance is being deleted. + """ + + timeout: Optional[int] = None + """ + Specifies the duration in seconds without any requests after which the + containers will be downscaled to their minimum scale value as defined by + `scale.min`. If set, this helps in optimizing resource usage by reducing the + number of container instances during periods of inactivity. + """ + + api_keys: Optional[List[str]] = None + """List of API keys for the inference instance""" diff --git a/src/gcore/types/cloud/inference/inference_deployment_api_key.py b/src/gcore/types/cloud/inference/inference_deployment_api_key.py new file mode 100644 index 00000000..e6df4ffa --- /dev/null +++ b/src/gcore/types/cloud/inference/inference_deployment_api_key.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["InferenceDeploymentAPIKey"] + + +class InferenceDeploymentAPIKey(BaseModel): + secret: str + """API key secret""" + + status: Literal["PENDING", "READY"] + """API key status""" diff --git a/src/gcore/types/cloud/inference/inference_flavor.py b/src/gcore/types/cloud/inference/inference_flavor.py new file mode 100644 index 00000000..26de9f31 --- /dev/null +++ b/src/gcore/types/cloud/inference/inference_flavor.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["InferenceFlavor"] + + +class InferenceFlavor(BaseModel): + cpu: float + """Inference flavor cpu count.""" + + description: str + """Inference flavor description.""" + + gpu: int + """Inference flavor gpu count.""" + + gpu_compute_capability: str + """Inference flavor gpu compute capability.""" + + gpu_memory: float + """Inference flavor gpu memory in Gi.""" + + gpu_model: str + """Inference flavor gpu model.""" + + is_gpu_shared: bool + """Inference flavor is gpu shared.""" + + memory: float + """Inference flavor memory in Gi.""" + + name: str + """Inference flavor name.""" diff --git a/src/gcore/types/cloud/inference/inference_registry_credentials.py b/src/gcore/types/cloud/inference/inference_registry_credentials.py new file mode 100644 index 00000000..db586719 --- /dev/null +++ b/src/gcore/types/cloud/inference/inference_registry_credentials.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["InferenceRegistryCredentials"] + + +class InferenceRegistryCredentials(BaseModel): + name: str + """Registry credential name.""" + + project_id: int + """Project ID to which the inference registry credentials belongs.""" + + registry_url: str + """Registry URL.""" + + username: str + """Registry username.""" diff --git a/src/gcore/types/cloud/inference/inference_secret.py b/src/gcore/types/cloud/inference/inference_secret.py new file mode 100644 index 00000000..0d6600db --- /dev/null +++ b/src/gcore/types/cloud/inference/inference_secret.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["InferenceSecret", "Data"] + + +class Data(BaseModel): + """Secret data.""" + + aws_access_key_id: str + """AWS IAM key ID.""" + + aws_secret_access_key: str + """AWS IAM secret key.""" + + +class InferenceSecret(BaseModel): + data: Data + """Secret data.""" + + name: str + """Secret name.""" + + type: str + """Secret type.""" diff --git a/src/gcore/types/cloud/inference/probe.py b/src/gcore/types/cloud/inference/probe.py new file mode 100644 index 00000000..952ee734 --- /dev/null +++ b/src/gcore/types/cloud/inference/probe.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel +from .probe_exec import ProbeExec +from .probe_http_get import ProbeHTTPGet +from .probe_tcp_socket import ProbeTcpSocket + +__all__ = ["Probe"] + + +class Probe(BaseModel): + exec: Optional[ProbeExec] = None + """Exec probe configuration""" + + failure_threshold: int + """The number of consecutive probe failures that mark the container as unhealthy.""" + + http_get: Optional[ProbeHTTPGet] = None + """HTTP GET probe configuration""" + + initial_delay_seconds: int + """The initial delay before starting the first probe.""" + + period_seconds: int + """How often (in seconds) to perform the probe.""" + + success_threshold: int + """The number of consecutive successful probes that mark the container as healthy.""" + + tcp_socket: Optional[ProbeTcpSocket] = None + """TCP socket probe configuration""" + + timeout_seconds: int + """The timeout for each probe.""" diff --git a/src/gcore/types/cloud/inference/probe_config.py b/src/gcore/types/cloud/inference/probe_config.py new file mode 100644 index 00000000..c4bc9eb5 --- /dev/null +++ b/src/gcore/types/cloud/inference/probe_config.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .probe import Probe +from ...._models import BaseModel + +__all__ = ["ProbeConfig"] + + +class ProbeConfig(BaseModel): + enabled: bool + """Whether the probe is enabled or not.""" + + probe: Optional[Probe] = None + """Probe configuration (exec, `http_get` or `tcp_socket`)""" diff --git a/src/gcore/types/cloud/inference/probe_exec.py b/src/gcore/types/cloud/inference/probe_exec.py new file mode 100644 index 00000000..8d5291f6 --- /dev/null +++ b/src/gcore/types/cloud/inference/probe_exec.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ...._models import BaseModel + +__all__ = ["ProbeExec"] + + +class ProbeExec(BaseModel): + command: List[str] + """Command to be executed inside the running container.""" diff --git a/src/gcore/types/cloud/inference/probe_http_get.py b/src/gcore/types/cloud/inference/probe_http_get.py new file mode 100644 index 00000000..081300f4 --- /dev/null +++ b/src/gcore/types/cloud/inference/probe_http_get.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel + +__all__ = ["ProbeHTTPGet"] + + +class ProbeHTTPGet(BaseModel): + headers: Dict[str, str] + """HTTP headers to be sent with the request.""" + + host: Optional[str] = None + """Host name to send HTTP request to.""" + + path: str + """The endpoint to send the HTTP request to.""" + + port: int + """Port number the probe should connect to.""" + + schema_: str = FieldInfo(alias="schema") + """Schema to use for the HTTP request.""" diff --git a/src/gcore/types/cloud/inference/probe_tcp_socket.py b/src/gcore/types/cloud/inference/probe_tcp_socket.py new file mode 100644 index 00000000..9dbfd869 --- /dev/null +++ b/src/gcore/types/cloud/inference/probe_tcp_socket.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["ProbeTcpSocket"] + + +class ProbeTcpSocket(BaseModel): + port: int + """Port number to check if it's open.""" diff --git a/src/gcore/types/cloud/inference/registry_credential_create_params.py b/src/gcore/types/cloud/inference/registry_credential_create_params.py new file mode 100644 index 00000000..c015816e --- /dev/null +++ b/src/gcore/types/cloud/inference/registry_credential_create_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RegistryCredentialCreateParams"] + + +class RegistryCredentialCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + name: Required[str] + """Registry credential name.""" + + password: Required[str] + """Registry password.""" + + registry_url: Required[str] + """Registry URL.""" + + username: Required[str] + """Registry username.""" diff --git a/src/gcore/types/cloud/inference/registry_credential_list_params.py b/src/gcore/types/cloud/inference/registry_credential_list_params.py new file mode 100644 index 00000000..a58555ed --- /dev/null +++ b/src/gcore/types/cloud/inference/registry_credential_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["RegistryCredentialListParams"] + + +class RegistryCredentialListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + limit: int + """Optional. Limit the number of returned items""" + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ diff --git a/src/gcore/types/cloud/inference/registry_credential_replace_params.py b/src/gcore/types/cloud/inference/registry_credential_replace_params.py new file mode 100644 index 00000000..d4df6de6 --- /dev/null +++ b/src/gcore/types/cloud/inference/registry_credential_replace_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RegistryCredentialReplaceParams"] + + +class RegistryCredentialReplaceParams(TypedDict, total=False): + project_id: int + """Project ID""" + + password: Required[str] + """Registry password.""" + + registry_url: Required[str] + """Registry URL.""" + + username: Required[str] + """Registry username.""" diff --git a/src/gcore/types/cloud/inference/secret_create_params.py b/src/gcore/types/cloud/inference/secret_create_params.py new file mode 100644 index 00000000..74817f1a --- /dev/null +++ b/src/gcore/types/cloud/inference/secret_create_params.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["SecretCreateParams", "Data"] + + +class SecretCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + data: Required[Data] + """Secret data.""" + + name: Required[str] + """Secret name.""" + + type: Required[str] + """Secret type. Currently only `aws-iam` is supported.""" + + +class Data(TypedDict, total=False): + """Secret data.""" + + aws_access_key_id: Required[str] + """AWS IAM key ID.""" + + aws_secret_access_key: Required[str] + """AWS IAM secret key.""" diff --git a/src/gcore/types/cloud/inference/secret_list_params.py b/src/gcore/types/cloud/inference/secret_list_params.py new file mode 100644 index 00000000..a264c9a1 --- /dev/null +++ b/src/gcore/types/cloud/inference/secret_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["SecretListParams"] + + +class SecretListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + limit: int + """Optional. Limit the number of returned items""" + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ diff --git a/src/gcore/types/cloud/inference/secret_replace_params.py b/src/gcore/types/cloud/inference/secret_replace_params.py new file mode 100644 index 00000000..be81a56e --- /dev/null +++ b/src/gcore/types/cloud/inference/secret_replace_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["SecretReplaceParams", "Data"] + + +class SecretReplaceParams(TypedDict, total=False): + project_id: int + """Project ID""" + + data: Required[Data] + """Secret data.""" + + type: Required[str] + """Secret type.""" + + +class Data(TypedDict, total=False): + """Secret data.""" + + aws_access_key_id: Required[str] + """AWS IAM key ID.""" + + aws_secret_access_key: Required[str] + """AWS IAM secret key.""" diff --git a/src/gcore/types/cloud/inference_region_capacity.py b/src/gcore/types/cloud/inference_region_capacity.py new file mode 100644 index 00000000..a10e2d6a --- /dev/null +++ b/src/gcore/types/cloud/inference_region_capacity.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel + +__all__ = ["InferenceRegionCapacity", "Capacity"] + + +class Capacity(BaseModel): + capacity: int + """Available capacity.""" + + flavor_name: str + """Flavor name.""" + + +class InferenceRegionCapacity(BaseModel): + capacity: List[Capacity] + """List of capacities by flavor.""" + + region_id: int + """Region ID.""" diff --git a/src/gcore/types/cloud/inference_region_capacity_list.py b/src/gcore/types/cloud/inference_region_capacity_list.py new file mode 100644 index 00000000..7bfd6ca1 --- /dev/null +++ b/src/gcore/types/cloud/inference_region_capacity_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .inference_region_capacity import InferenceRegionCapacity + +__all__ = ["InferenceRegionCapacityList"] + + +class InferenceRegionCapacityList(BaseModel): + count: int + """Number of objects""" + + results: List[InferenceRegionCapacity] + """Objects""" diff --git a/src/gcore/types/cloud/instance.py b/src/gcore/types/cloud/instance.py new file mode 100644 index 00000000..14bac8b3 --- /dev/null +++ b/src/gcore/types/cloud/instance.py @@ -0,0 +1,308 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, TypeAlias + +from .tag import Tag +from ..._models import BaseModel +from .ddos_profile import DDOSProfile +from .fixed_address import FixedAddress +from .blackhole_port import BlackholePort +from .floating_address import FloatingAddress +from .instance_isolation import InstanceIsolation +from .fixed_address_short import FixedAddressShort + +__all__ = [ + "Instance", + "Address", + "FixedIPAssignment", + "Flavor", + "FlavorInstanceFlavorSerializer", + "FlavorInstanceFlavorSerializerHardwareDescription", + "FlavorBareMetalFlavorSerializer", + "FlavorBareMetalFlavorSerializerHardwareDescription", + "FlavorDeprecatedGPUClusterFlavorSerializer", + "FlavorDeprecatedGPUClusterFlavorSerializerHardwareDescription", + "SecurityGroup", + "Volume", +] + +Address: TypeAlias = Union[FloatingAddress, FixedAddressShort, FixedAddress] + + +class FixedIPAssignment(BaseModel): + external: bool + """Is network external""" + + ip_address: str + """Ip address""" + + subnet_id: str + """Interface subnet id""" + + +class FlavorInstanceFlavorSerializerHardwareDescription(BaseModel): + """Additional hardware description""" + + ram: str + """RAM description""" + + vcpus: str + """CPU description""" + + +class FlavorInstanceFlavorSerializer(BaseModel): + """Instances flavor schema embedded into instance schema""" + + architecture: str + """CPU architecture""" + + flavor_id: str + """Flavor ID is the same as name""" + + flavor_name: str + """Flavor name""" + + hardware_description: FlavorInstanceFlavorSerializerHardwareDescription + """Additional hardware description""" + + os_type: str + """Flavor operating system""" + + ram: int + """RAM size in MiB""" + + vcpus: int + """Virtual CPU count. For bare metal flavors, it's a physical CPU count""" + + +class FlavorBareMetalFlavorSerializerHardwareDescription(BaseModel): + """Additional hardware description""" + + cpu: str + """Human-readable CPU description""" + + disk: str + """Human-readable disk description""" + + license: str + """If the flavor is licensed, this field contains the license type""" + + network: str + """Human-readable NIC description""" + + ram: str + """Human-readable RAM description""" + + +class FlavorBareMetalFlavorSerializer(BaseModel): + """Bare metal flavor schema embedded into instance schema""" + + architecture: str + """CPU architecture""" + + flavor_id: str + """Flavor ID is the same as name""" + + flavor_name: str + """Flavor name""" + + hardware_description: FlavorBareMetalFlavorSerializerHardwareDescription + """Additional hardware description""" + + os_type: str + """Operating system""" + + ram: int + """RAM size in MiB""" + + resource_class: str + """Flavor resource class for mapping to hardware capacity""" + + vcpus: int + """Virtual CPU count. For bare metal flavors, it's a physical CPU count""" + + +class FlavorDeprecatedGPUClusterFlavorSerializerHardwareDescription(BaseModel): + """Additional hardware description""" + + cpu: str + """Human-readable CPU description""" + + disk: str + """Human-readable disk description""" + + gpu: str + """Human-readable GPU description""" + + license: str + """If the flavor is licensed, this field contains the license type""" + + network: str + """Human-readable NIC description""" + + ram: str + """Human-readable RAM description""" + + +class FlavorDeprecatedGPUClusterFlavorSerializer(BaseModel): + """GPU cluster flavor schema embedded into instance schema""" + + architecture: str + """CPU architecture""" + + flavor_id: str + """Flavor ID is the same as name""" + + flavor_name: str + """Flavor name""" + + hardware_description: FlavorDeprecatedGPUClusterFlavorSerializerHardwareDescription + """Additional hardware description""" + + os_type: str + """Operating system""" + + ram: int + """RAM size in MiB""" + + resource_class: str + """Flavor resource class for mapping to hardware capacity""" + + vcpus: int + """Virtual CPU count. For bare metal flavors, it's a physical CPU count""" + + +Flavor: TypeAlias = Union[ + FlavorInstanceFlavorSerializer, FlavorBareMetalFlavorSerializer, FlavorDeprecatedGPUClusterFlavorSerializer +] + + +class SecurityGroup(BaseModel): + name: str + """Name.""" + + +class Volume(BaseModel): + id: str + """Volume ID""" + + delete_on_termination: bool + """Whether the volume is deleted together with the VM""" + + +class Instance(BaseModel): + id: str + """Instance ID""" + + addresses: Dict[str, List[Address]] + """Map of `network_name` to list of addresses in that network""" + + blackhole_ports: List[BlackholePort] + """IP addresses of the instances that are blackholed by DDoS mitigation system""" + + created_at: datetime + """Datetime when instance was created""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + ddos_profile: Optional[DDOSProfile] = None + """Advanced DDoS protection profile. + + It is always `null` if query parameter `with_ddos=true` is not set. + """ + + fixed_ip_assignments: Optional[List[FixedIPAssignment]] = None + """Fixed IP assigned to instance""" + + flavor: Flavor + """Flavor""" + + instance_description: Optional[str] = None + """Instance description""" + + instance_isolation: Optional[InstanceIsolation] = None + """Instance isolation information""" + + name: str + """Instance name""" + + project_id: int + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + security_groups: List[SecurityGroup] + """Security groups""" + + ssh_key_name: Optional[str] = None + """SSH key assigned to instance""" + + status: Literal[ + "ACTIVE", + "BUILD", + "DELETED", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PASSWORD", + "PAUSED", + "REBOOT", + "REBUILD", + "RESCUE", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "UNKNOWN", + "VERIFY_RESIZE", + ] + """Instance status""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + task_state: Optional[str] = None + """Task state""" + + vm_state: Literal[ + "active", + "building", + "deleted", + "error", + "paused", + "rescued", + "resized", + "shelved", + "shelved_offloaded", + "soft-deleted", + "stopped", + "suspended", + ] + """Virtual machine state (active)""" + + volumes: List[Volume] + """List of volumes""" diff --git a/src/gcore/types/cloud/instance_action_params.py b/src/gcore/types/cloud/instance_action_params.py new file mode 100644 index 00000000..c7f3ca8f --- /dev/null +++ b/src/gcore/types/cloud/instance_action_params.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = ["InstanceActionParams", "StartActionInstanceSerializer", "BasicActionInstanceSerializer"] + + +class StartActionInstanceSerializer(TypedDict, total=False): + project_id: int + + region_id: int + + action: Required[Literal["start"]] + """Instance action name""" + + activate_profile: Optional[bool] + """Used on start instance to activate Advanced DDoS profile""" + + +class BasicActionInstanceSerializer(TypedDict, total=False): + project_id: int + + region_id: int + + action: Required[Literal["reboot", "reboot_hard", "resume", "stop", "suspend"]] + """Instance action name""" + + +InstanceActionParams: TypeAlias = Union[StartActionInstanceSerializer, BasicActionInstanceSerializer] diff --git a/src/gcore/types/cloud/instance_add_to_placement_group_params.py b/src/gcore/types/cloud/instance_add_to_placement_group_params.py new file mode 100644 index 00000000..866f105b --- /dev/null +++ b/src/gcore/types/cloud/instance_add_to_placement_group_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["InstanceAddToPlacementGroupParams"] + + +class InstanceAddToPlacementGroupParams(TypedDict, total=False): + project_id: int + + region_id: int + + servergroup_id: Required[str] + """Anti-affinity or affinity or soft-anti-affinity server group ID.""" diff --git a/src/gcore/types/cloud/instance_assign_security_group_params.py b/src/gcore/types/cloud/instance_assign_security_group_params.py new file mode 100644 index 00000000..a963ae34 --- /dev/null +++ b/src/gcore/types/cloud/instance_assign_security_group_params.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Required, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["InstanceAssignSecurityGroupParams", "PortsSecurityGroupName"] + + +class InstanceAssignSecurityGroupParams(TypedDict, total=False): + project_id: int + + region_id: int + + name: str + """Security group name, applies to all ports""" + + ports_security_group_names: Iterable[PortsSecurityGroupName] + """Port security groups mapping""" + + +class PortsSecurityGroupName(TypedDict, total=False): + """Port security group names""" + + port_id: Required[Optional[str]] + """Port ID. If None, security groups will be applied to all ports""" + + security_group_names: Required[SequenceNotStr[str]] + """List of security group names""" diff --git a/src/gcore/types/cloud/instance_create_params.py b/src/gcore/types/cloud/instance_create_params.py new file mode 100644 index 00000000..bed6de52 --- /dev/null +++ b/src/gcore/types/cloud/instance_create_params.py @@ -0,0 +1,629 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .interface_ip_family import InterfaceIPFamily + +__all__ = [ + "InstanceCreateParams", + "Interface", + "InterfaceNewInterfaceExternalSerializerPydantic", + "InterfaceNewInterfaceExternalSerializerPydanticSecurityGroup", + "InterfaceNewInterfaceSpecificSubnetFipSerializerPydantic", + "InterfaceNewInterfaceSpecificSubnetFipSerializerPydanticFloatingIP", + "InterfaceNewInterfaceSpecificSubnetFipSerializerPydanticFloatingIPNewInstanceFloatingIPInterfaceSerializer", + "InterfaceNewInterfaceSpecificSubnetFipSerializerPydanticFloatingIPExistingInstanceFloatingIPInterfaceSerializer", + "InterfaceNewInterfaceSpecificSubnetFipSerializerPydanticSecurityGroup", + "InterfaceNewInterfaceAnySubnetFipSerializerPydantic", + "InterfaceNewInterfaceAnySubnetFipSerializerPydanticFloatingIP", + "InterfaceNewInterfaceAnySubnetFipSerializerPydanticFloatingIPNewInstanceFloatingIPInterfaceSerializer", + "InterfaceNewInterfaceAnySubnetFipSerializerPydanticFloatingIPExistingInstanceFloatingIPInterfaceSerializer", + "InterfaceNewInterfaceAnySubnetFipSerializerPydanticSecurityGroup", + "InterfaceNewInterfaceReservedFixedIPFipSerializerPydantic", + "InterfaceNewInterfaceReservedFixedIPFipSerializerPydanticFloatingIP", + "InterfaceNewInterfaceReservedFixedIPFipSerializerPydanticFloatingIPNewInstanceFloatingIPInterfaceSerializer", + "InterfaceNewInterfaceReservedFixedIPFipSerializerPydanticFloatingIPExistingInstanceFloatingIPInterfaceSerializer", + "InterfaceNewInterfaceReservedFixedIPFipSerializerPydanticSecurityGroup", + "Volume", + "VolumeCreateInstanceCreateNewVolumeSerializer", + "VolumeCreateInstanceCreateVolumeFromImageSerializer", + "VolumeCreateInstanceCreateVolumeFromSnapshotSerializer", + "VolumeCreateInstanceCreateVolumeFromApptemplateSerializer", + "VolumeCreateInstanceExistingVolumeSerializer", + "SecurityGroup", +] + + +class InstanceCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + flavor: Required[str] + """The flavor of the instance.""" + + interfaces: Required[Iterable[Interface]] + """A list of network interfaces for the instance. + + You can create one or more interfaces - private, public, or both. + """ + + volumes: Required[Iterable[Volume]] + """List of volumes that will be attached to the instance.""" + + allow_app_ports: bool + """Set to `true` if creating the instance from an `apptemplate`. + + This allows application ports in the security group for instances created from a + marketplace application template. + """ + + configuration: Optional[Dict[str, object]] + """ + Parameters for the application template if creating the instance from an + `apptemplate`. + """ + + name: str + """Instance name.""" + + name_template: str + """ + If you want the instance name to be automatically generated based on IP + addresses, you can provide a name template instead of specifying the name + manually. The template should include a placeholder that will be replaced during + provisioning. Supported placeholders are: `{ip_octets}` (last 3 octets of the + IP), `{two_ip_octets}`, and `{one_ip_octet}`. + """ + + password: str + """For Linux instances, 'username' and 'password' are used to create a new user. + + When only 'password' is provided, it is set as the password for the default user + of the image. For Windows instances, 'username' cannot be specified. Use the + 'password' field to set the password for the 'Admin' user on Windows. Use the + 'user_data' field to provide a script to create new users on Windows. The + password of the Admin user cannot be updated via 'user_data'. + """ + + security_groups: Iterable[SecurityGroup] + """ + Specifies security group UUIDs to be applied to all instance network interfaces. + """ + + servergroup_id: str + """Placement group ID for instance placement policy. + + Supported group types: + + - `anti-affinity`: Ensures instances are placed on different hosts for high + availability. + - `affinity`: Places instances on the same host for low-latency communication. + - `soft-anti-affinity`: Tries to place instances on different hosts but allows + sharing if needed. + """ + + ssh_key_name: Optional[str] + """ + Specifies the name of the SSH keypair, created via the + [/v1/`ssh_keys` endpoint](/docs/api-reference/cloud/ssh-keys/add-or-generate-ssh-key). + """ + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + user_data: str + """String in base64 format. + + For Linux instances, 'user_data' is ignored when 'password' field is provided. + For Windows instances, Admin user password is set by 'password' field and cannot + be updated via 'user_data'. Examples of the `user_data`: + https://cloudinit.readthedocs.io/en/latest/topics/examples.html + """ + + username: str + """For Linux instances, 'username' and 'password' are used to create a new user. + + For Windows instances, 'username' cannot be specified. Use 'password' field to + set the password for the 'Admin' user on Windows. + """ + + +class InterfaceNewInterfaceExternalSerializerPydanticSecurityGroup(TypedDict, total=False): + id: Required[str] + """Resource ID""" + + +class InterfaceNewInterfaceExternalSerializerPydantic(TypedDict, total=False): + """Instance will be attached to default external network""" + + type: Required[Literal["external"]] + """A public IP address will be assigned to the instance.""" + + interface_name: str + """Interface name. + + Defaults to `null` and is returned as `null` in the API response if not set. + """ + + ip_family: Optional[InterfaceIPFamily] + """Specify `ipv4`, `ipv6`, or `dual` to enable both.""" + + security_groups: Iterable[InterfaceNewInterfaceExternalSerializerPydanticSecurityGroup] + """Specifies security group UUIDs to be applied to the instance network interface.""" + + +class InterfaceNewInterfaceSpecificSubnetFipSerializerPydanticFloatingIPNewInstanceFloatingIPInterfaceSerializer( + TypedDict, total=False +): + source: Required[Literal["new"]] + """A new floating IP will be created and attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +class InterfaceNewInterfaceSpecificSubnetFipSerializerPydanticFloatingIPExistingInstanceFloatingIPInterfaceSerializer( + TypedDict, total=False +): + existing_floating_id: Required[str] + """ + An existing available floating IP id must be specified if the source is set to + `existing` + """ + + source: Required[Literal["existing"]] + """An existing available floating IP will be attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +InterfaceNewInterfaceSpecificSubnetFipSerializerPydanticFloatingIP: TypeAlias = Union[ + InterfaceNewInterfaceSpecificSubnetFipSerializerPydanticFloatingIPNewInstanceFloatingIPInterfaceSerializer, + InterfaceNewInterfaceSpecificSubnetFipSerializerPydanticFloatingIPExistingInstanceFloatingIPInterfaceSerializer, +] + + +class InterfaceNewInterfaceSpecificSubnetFipSerializerPydanticSecurityGroup(TypedDict, total=False): + id: Required[str] + """Resource ID""" + + +class InterfaceNewInterfaceSpecificSubnetFipSerializerPydantic(TypedDict, total=False): + """ + The instance will get an IP address from the selected network. + If you choose to add a floating IP, the instance will be reachable from the internet. + Otherwise, it will only have a private IP within the network. + """ + + network_id: Required[str] + """The network where the instance will be connected.""" + + subnet_id: Required[str] + """The instance will get an IP address from this subnet.""" + + type: Required[Literal["subnet"]] + """The instance will get an IP address from the selected network. + + If you choose to add a floating IP, the instance will be reachable from the + internet. Otherwise, it will only have a private IP within the network. + """ + + floating_ip: InterfaceNewInterfaceSpecificSubnetFipSerializerPydanticFloatingIP + """Allows the instance to have a public IP that can be reached from the internet.""" + + interface_name: str + """Interface name. + + Defaults to `null` and is returned as `null` in the API response if not set. + """ + + security_groups: Iterable[InterfaceNewInterfaceSpecificSubnetFipSerializerPydanticSecurityGroup] + """Specifies security group UUIDs to be applied to the instance network interface.""" + + +class InterfaceNewInterfaceAnySubnetFipSerializerPydanticFloatingIPNewInstanceFloatingIPInterfaceSerializer( + TypedDict, total=False +): + source: Required[Literal["new"]] + """A new floating IP will be created and attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +class InterfaceNewInterfaceAnySubnetFipSerializerPydanticFloatingIPExistingInstanceFloatingIPInterfaceSerializer( + TypedDict, total=False +): + existing_floating_id: Required[str] + """ + An existing available floating IP id must be specified if the source is set to + `existing` + """ + + source: Required[Literal["existing"]] + """An existing available floating IP will be attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +InterfaceNewInterfaceAnySubnetFipSerializerPydanticFloatingIP: TypeAlias = Union[ + InterfaceNewInterfaceAnySubnetFipSerializerPydanticFloatingIPNewInstanceFloatingIPInterfaceSerializer, + InterfaceNewInterfaceAnySubnetFipSerializerPydanticFloatingIPExistingInstanceFloatingIPInterfaceSerializer, +] + + +class InterfaceNewInterfaceAnySubnetFipSerializerPydanticSecurityGroup(TypedDict, total=False): + id: Required[str] + """Resource ID""" + + +class InterfaceNewInterfaceAnySubnetFipSerializerPydantic(TypedDict, total=False): + network_id: Required[str] + """The network where the instance will be connected.""" + + type: Required[Literal["any_subnet"]] + """Instance will be attached to a subnet with the largest count of free IPs.""" + + floating_ip: InterfaceNewInterfaceAnySubnetFipSerializerPydanticFloatingIP + """Allows the instance to have a public IP that can be reached from the internet.""" + + interface_name: str + """Interface name. + + Defaults to `null` and is returned as `null` in the API response if not set. + """ + + ip_address: str + """You can specify a specific IP address from your subnet.""" + + ip_family: Optional[InterfaceIPFamily] + """Specify `ipv4`, `ipv6`, or `dual` to enable both.""" + + security_groups: Iterable[InterfaceNewInterfaceAnySubnetFipSerializerPydanticSecurityGroup] + """Specifies security group UUIDs to be applied to the instance network interface.""" + + +class InterfaceNewInterfaceReservedFixedIPFipSerializerPydanticFloatingIPNewInstanceFloatingIPInterfaceSerializer( + TypedDict, total=False +): + source: Required[Literal["new"]] + """A new floating IP will be created and attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +class InterfaceNewInterfaceReservedFixedIPFipSerializerPydanticFloatingIPExistingInstanceFloatingIPInterfaceSerializer( + TypedDict, total=False +): + existing_floating_id: Required[str] + """ + An existing available floating IP id must be specified if the source is set to + `existing` + """ + + source: Required[Literal["existing"]] + """An existing available floating IP will be attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +InterfaceNewInterfaceReservedFixedIPFipSerializerPydanticFloatingIP: TypeAlias = Union[ + InterfaceNewInterfaceReservedFixedIPFipSerializerPydanticFloatingIPNewInstanceFloatingIPInterfaceSerializer, + InterfaceNewInterfaceReservedFixedIPFipSerializerPydanticFloatingIPExistingInstanceFloatingIPInterfaceSerializer, +] + + +class InterfaceNewInterfaceReservedFixedIPFipSerializerPydanticSecurityGroup(TypedDict, total=False): + id: Required[str] + """Resource ID""" + + +class InterfaceNewInterfaceReservedFixedIPFipSerializerPydantic(TypedDict, total=False): + port_id: Required[str] + """Network ID the subnet belongs to. Port will be plugged in this network.""" + + type: Required[Literal["reserved_fixed_ip"]] + """An existing available reserved fixed IP will be attached to the instance. + + If the reserved IP is not public and you choose to add a floating IP, the + instance will be accessible from the internet. + """ + + floating_ip: InterfaceNewInterfaceReservedFixedIPFipSerializerPydanticFloatingIP + """Allows the instance to have a public IP that can be reached from the internet.""" + + interface_name: str + """Interface name. + + Defaults to `null` and is returned as `null` in the API response if not set. + """ + + security_groups: Iterable[InterfaceNewInterfaceReservedFixedIPFipSerializerPydanticSecurityGroup] + """Specifies security group UUIDs to be applied to the instance network interface.""" + + +Interface: TypeAlias = Union[ + InterfaceNewInterfaceExternalSerializerPydantic, + InterfaceNewInterfaceSpecificSubnetFipSerializerPydantic, + InterfaceNewInterfaceAnySubnetFipSerializerPydantic, + InterfaceNewInterfaceReservedFixedIPFipSerializerPydantic, +] + + +class VolumeCreateInstanceCreateNewVolumeSerializer(TypedDict, total=False): + size: Required[int] + """Volume size in GiB.""" + + source: Required[Literal["new-volume"]] + """New volume will be created from scratch and attached to the instance.""" + + attachment_tag: str + """Block device attachment tag (not exposed in the normal tags)""" + + delete_on_termination: bool + """Set to `true` to automatically delete the volume when the instance is deleted.""" + + name: str + """The name of the volume. + + If not specified, a name will be generated automatically. + """ + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] + """Volume type name. Supported values: + + - `standard` - Network SSD block storage offering stable performance with high + random I/O and data reliability (6 IOPS per 1 GiB, 0.4 MB/s per 1 GiB). Max + IOPS: 4500. Max bandwidth: 300 MB/s. + - `ssd_hiiops` - High-performance SSD storage for latency-sensitive + transactional workloads (60 IOPS per 1 GiB, 2.5 MB/s per 1 GiB). Max + IOPS: 9000. Max bandwidth: 500 MB/s. + - `ssd_lowlatency` - SSD storage optimized for low-latency and real-time + processing. Max IOPS: 5000. Average latency: 300 µs. Snapshots and volume + resizing are **not** supported for `ssd_lowlatency`. + """ + + +class VolumeCreateInstanceCreateVolumeFromImageSerializer(TypedDict, total=False): + image_id: Required[str] + """Image ID.""" + + source: Required[Literal["image"]] + """New volume will be created from the image and attached to the instance. + + Specify `boot_index=0` to boot from this volume. + """ + + attachment_tag: str + """Block device attachment tag (not exposed in the normal tags)""" + + boot_index: int + """ + - `0` means that this is the primary boot device; + - A unique positive value is set for the secondary bootable devices; + - A negative number means that the boot is prohibited. + """ + + delete_on_termination: bool + """Set to `true` to automatically delete the volume when the instance is deleted.""" + + name: str + """The name of the volume. + + If not specified, a name will be generated automatically. + """ + + size: int + """Volume size in GiB. + + - For instances: **specify the desired volume size explicitly**. + - For basic VMs: the size is set automatically based on the flavor. + """ + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] + """Volume type name. Supported values: + + - `standard` - Network SSD block storage offering stable performance with high + random I/O and data reliability (6 IOPS per 1 GiB, 0.4 MB/s per 1 GiB). Max + IOPS: 4500. Max bandwidth: 300 MB/s. + - `ssd_hiiops` - High-performance SSD storage for latency-sensitive + transactional workloads (60 IOPS per 1 GiB, 2.5 MB/s per 1 GiB). Max + IOPS: 9000. Max bandwidth: 500 MB/s. + - `ssd_lowlatency` - SSD storage optimized for low-latency and real-time + processing. Max IOPS: 5000. Average latency: 300 µs. Snapshots and volume + resizing are **not** supported for `ssd_lowlatency`. + """ + + +class VolumeCreateInstanceCreateVolumeFromSnapshotSerializer(TypedDict, total=False): + size: Required[int] + """Volume size in GiB.""" + + snapshot_id: Required[str] + """Snapshot ID.""" + + source: Required[Literal["snapshot"]] + """New volume will be created from the snapshot and attached to the instance.""" + + attachment_tag: str + """Block device attachment tag (not exposed in the normal tags)""" + + boot_index: int + """ + - `0` means that this is the primary boot device; + - A unique positive value is set for the secondary bootable devices; + - A negative number means that the boot is prohibited. + """ + + delete_on_termination: bool + """Set to `true` to automatically delete the volume when the instance is deleted.""" + + name: str + """The name of the volume. + + If not specified, a name will be generated automatically. + """ + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + type_name: Literal["ssd_hiiops", "standard"] + """Specifies the volume type. + + If omitted, the type from the source volume will be used by default. + """ + + +class VolumeCreateInstanceCreateVolumeFromApptemplateSerializer(TypedDict, total=False): + apptemplate_id: Required[str] + """App template ID.""" + + source: Required[Literal["apptemplate"]] + """New volume will be created from the app template and attached to the instance.""" + + attachment_tag: str + """Block device attachment tag (not exposed in the normal tags)""" + + boot_index: int + """ + - `0` means that this is the primary boot device; + - A unique positive value is set for the secondary bootable devices; + - A negative number means that the boot is prohibited. + """ + + delete_on_termination: bool + """Set to `true` to automatically delete the volume when the instance is deleted.""" + + name: str + """The name of the volume. + + If not specified, a name will be generated automatically. + """ + + size: int + """Volume size in GiB.""" + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] + """Volume type name. Supported values: + + - `standard` - Network SSD block storage offering stable performance with high + random I/O and data reliability (6 IOPS per 1 GiB, 0.4 MB/s per 1 GiB). Max + IOPS: 4500. Max bandwidth: 300 MB/s. + - `ssd_hiiops` - High-performance SSD storage for latency-sensitive + transactional workloads (60 IOPS per 1 GiB, 2.5 MB/s per 1 GiB). Max + IOPS: 9000. Max bandwidth: 500 MB/s. + - `ssd_lowlatency` - SSD storage optimized for low-latency and real-time + processing. Max IOPS: 5000. Average latency: 300 µs. Snapshots and volume + resizing are **not** supported for `ssd_lowlatency`. + """ + + +class VolumeCreateInstanceExistingVolumeSerializer(TypedDict, total=False): + source: Required[Literal["existing-volume"]] + """Existing available volume will be attached to the instance.""" + + volume_id: Required[str] + """Volume ID.""" + + attachment_tag: str + """Block device attachment tag (not exposed in the normal tags)""" + + boot_index: int + """ + - `0` means that this is the primary boot device; + - A unique positive value is set for the secondary bootable devices; + - A negative number means that the boot is prohibited. + """ + + delete_on_termination: bool + """Set to `true` to automatically delete the volume when the instance is deleted.""" + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + +Volume: TypeAlias = Union[ + VolumeCreateInstanceCreateNewVolumeSerializer, + VolumeCreateInstanceCreateVolumeFromImageSerializer, + VolumeCreateInstanceCreateVolumeFromSnapshotSerializer, + VolumeCreateInstanceCreateVolumeFromApptemplateSerializer, + VolumeCreateInstanceExistingVolumeSerializer, +] + + +class SecurityGroup(TypedDict, total=False): + id: Required[str] + """Resource ID""" diff --git a/src/gcore/types/cloud/instance_delete_params.py b/src/gcore/types/cloud/instance_delete_params.py new file mode 100644 index 00000000..56bf4a29 --- /dev/null +++ b/src/gcore/types/cloud/instance_delete_params.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["InstanceDeleteParams"] + + +class InstanceDeleteParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + delete_floatings: bool + """True if it is required to delete floating IPs assigned to the instance. + + Can't be used with `floatings`. + """ + + floatings: str + """Comma separated list of floating ids that should be deleted. + + Can't be used with `delete_floatings`. + """ + + reserved_fixed_ips: str + """Comma separated list of port IDs to be deleted with the instance""" + + volumes: str + """Comma separated list of volume IDs to be deleted with the instance""" diff --git a/src/gcore/types/cloud/instance_get_console_params.py b/src/gcore/types/cloud/instance_get_console_params.py new file mode 100644 index 00000000..eb2df351 --- /dev/null +++ b/src/gcore/types/cloud/instance_get_console_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["InstanceGetConsoleParams"] + + +class InstanceGetConsoleParams(TypedDict, total=False): + project_id: int + + region_id: int + + console_type: str + """Console type""" diff --git a/src/gcore/types/cloud/instance_interface.py b/src/gcore/types/cloud/instance_interface.py new file mode 100644 index 00000000..1f4e0fb6 --- /dev/null +++ b/src/gcore/types/cloud/instance_interface.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .floating_ip import FloatingIP +from .ip_assignment import IPAssignment +from .network_details import NetworkDetails +from .allowed_address_pairs import AllowedAddressPairs + +__all__ = ["InstanceInterface"] + + +class InstanceInterface(BaseModel): + allowed_address_pairs: List[AllowedAddressPairs] + """Group of subnet masks and/or IP addresses that share the current IP as VIP""" + + floatingip_details: List[FloatingIP] + """Bodies of floating IPs that are NAT-ing IPs of this port""" + + ip_assignments: List[IPAssignment] + """IP addresses assigned to this port""" + + network_details: NetworkDetails + """Body of the network this port is attached to""" + + network_id: str + """ID of the network the port is attached to""" + + port_id: str + """ID of virtual ethernet port object""" + + port_security_enabled: bool + """Port security status""" + + interface_name: Optional[str] = None + """Interface name""" + + mac_address: Optional[str] = None + """MAC address of the virtual port""" diff --git a/src/gcore/types/cloud/instance_isolation.py b/src/gcore/types/cloud/instance_isolation.py new file mode 100644 index 00000000..988d4a34 --- /dev/null +++ b/src/gcore/types/cloud/instance_isolation.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["InstanceIsolation"] + + +class InstanceIsolation(BaseModel): + reason: Optional[str] = None + """The reason of instance isolation if it is isolated from external internet.""" diff --git a/src/gcore/types/cloud/instance_list.py b/src/gcore/types/cloud/instance_list.py new file mode 100644 index 00000000..158812ec --- /dev/null +++ b/src/gcore/types/cloud/instance_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from .instance import Instance +from ..._models import BaseModel + +__all__ = ["InstanceList"] + + +class InstanceList(BaseModel): + count: int + """Number of objects""" + + results: List[Instance] + """Objects""" diff --git a/src/gcore/types/cloud/instance_list_params.py b/src/gcore/types/cloud/instance_list_params.py new file mode 100644 index 00000000..1d321ffc --- /dev/null +++ b/src/gcore/types/cloud/instance_list_params.py @@ -0,0 +1,143 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Literal, Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = ["InstanceListParams"] + + +class InstanceListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + available_floating: bool + """Only show instances which are able to handle floating address""" + + changes_before: Annotated[Union[str, datetime], PropertyInfo(alias="changes-before", format="iso8601")] + """Filters the instances by a date and time stamp when the instances last changed.""" + + changes_since: Annotated[Union[str, datetime], PropertyInfo(alias="changes-since", format="iso8601")] + """ + Filters the instances by a date and time stamp when the instances last changed + status. + """ + + exclude_flavor_prefix: str + """Exclude instances with specified flavor prefix""" + + exclude_secgroup: str + """Exclude instances with specified security group name""" + + flavor_id: str + """Filter out instances by `flavor_id`. Flavor id must match exactly.""" + + flavor_prefix: str + """Filter out instances by `flavor_prefix`.""" + + include_ai: bool + """Include GPU clusters' servers""" + + include_baremetal: bool + """Include bare metal servers. Please, use `GET /v1/bminstances/` instead""" + + include_k8s: bool + """Include managed k8s worker nodes""" + + ip: str + """An IPv4 address to filter results by. + + Note: partial matches are allowed. For example, searching for 192.168.0.1 will + return 192.168.0.1, 192.168.0.10, 192.168.0.110, and so on. + """ + + limit: int + """Optional. Limit the number of returned items""" + + name: str + """Filter instances by name. + + You can provide a full or partial name, instances with matching names will be + returned. For example, entering 'test' will return all instances that contain + 'test' in their name. + """ + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ + + only_isolated: bool + """Include only isolated instances""" + + only_with_fixed_external_ip: bool + """Return bare metals only with external fixed IP addresses.""" + + order_by: Literal["created.asc", "created.desc", "name.asc", "name.desc", "status.asc", "status.desc"] + """Order by field and direction.""" + + profile_name: str + """Filter result by ddos protection profile name. + + Effective only with `with_ddos` set to true. + """ + + protection_status: Literal["Active", "Queued", "Error"] + """Filter result by DDoS `protection_status`. + + if parameter is provided. Effective only with `with_ddos` set to true. (Active, + Queued or Error) + """ + + status: Literal[ + "ACTIVE", + "BUILD", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PAUSED", + "REBOOT", + "REBUILD", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "VERIFY_RESIZE", + ] + """Filters instances by status.""" + + tag_key_value: str + """Optional. Filter by tag key-value pairs.""" + + tag_value: SequenceNotStr[str] + """Optional. Filter by tag values. ?`tag_value`=value1&`tag_value`=value2""" + + type_ddos_profile: Literal["basic", "advanced"] + """Return bare metals either only with advanced or only basic DDoS protection. + + Effective only with `with_ddos` set to true. (advanced or basic) + """ + + uuid: str + """Filter the server list result by the UUID of the server. Allowed UUID part""" + + with_ddos: bool + """Include DDoS profile information in the response when set to `true`. + + Otherwise, the `ddos_profile` field in the response is `null` by default. + """ + + with_interfaces_name: bool + """Include `interface_name` in the addresses""" diff --git a/src/gcore/types/cloud/instance_metrics_time_unit.py b/src/gcore/types/cloud/instance_metrics_time_unit.py new file mode 100644 index 00000000..63f2bcdd --- /dev/null +++ b/src/gcore/types/cloud/instance_metrics_time_unit.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["InstanceMetricsTimeUnit"] + +InstanceMetricsTimeUnit: TypeAlias = Literal["day", "hour"] diff --git a/src/gcore/types/cloud/instance_resize_params.py b/src/gcore/types/cloud/instance_resize_params.py new file mode 100644 index 00000000..99b3abe5 --- /dev/null +++ b/src/gcore/types/cloud/instance_resize_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["InstanceResizeParams"] + + +class InstanceResizeParams(TypedDict, total=False): + project_id: int + + region_id: int + + flavor_id: Required[str] + """Flavor ID""" diff --git a/src/gcore/types/cloud/instance_unassign_security_group_params.py b/src/gcore/types/cloud/instance_unassign_security_group_params.py new file mode 100644 index 00000000..030a2b6b --- /dev/null +++ b/src/gcore/types/cloud/instance_unassign_security_group_params.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Required, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["InstanceUnassignSecurityGroupParams", "PortsSecurityGroupName"] + + +class InstanceUnassignSecurityGroupParams(TypedDict, total=False): + project_id: int + + region_id: int + + name: str + """Security group name, applies to all ports""" + + ports_security_group_names: Iterable[PortsSecurityGroupName] + """Port security groups mapping""" + + +class PortsSecurityGroupName(TypedDict, total=False): + """Port security group names""" + + port_id: Required[Optional[str]] + """Port ID. If None, security groups will be applied to all ports""" + + security_group_names: Required[SequenceNotStr[str]] + """List of security group names""" diff --git a/src/gcore/types/cloud/instance_update_params.py b/src/gcore/types/cloud/instance_update_params.py new file mode 100644 index 00000000..d3c2c7ce --- /dev/null +++ b/src/gcore/types/cloud/instance_update_params.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +from .tag_update_map_param import TagUpdateMapParam + +__all__ = ["InstanceUpdateParams"] + + +class InstanceUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: str + """Name""" + + tags: Optional[TagUpdateMapParam] + """Update key-value tags using JSON Merge Patch semantics (RFC 7386). + + Provide key-value pairs to add or update tags. Set tag values to `null` to + remove tags. Unspecified tags remain unchanged. Read-only tags are always + preserved and cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + """ diff --git a/src/gcore/types/cloud/instances/__init__.py b/src/gcore/types/cloud/instances/__init__.py new file mode 100644 index 00000000..fb06e51e --- /dev/null +++ b/src/gcore/types/cloud/instances/__init__.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .metrics import Metrics as Metrics +from .metrics_list import MetricsList as MetricsList +from .image_get_params import ImageGetParams as ImageGetParams +from .image_list_params import ImageListParams as ImageListParams +from .flavor_list_params import FlavorListParams as FlavorListParams +from .metric_list_params import MetricListParams as MetricListParams +from .image_update_params import ImageUpdateParams as ImageUpdateParams +from .image_upload_params import ImageUploadParams as ImageUploadParams +from .instance_flavor_list import InstanceFlavorList as InstanceFlavorList +from .interface_attach_params import InterfaceAttachParams as InterfaceAttachParams +from .interface_detach_params import InterfaceDetachParams as InterfaceDetachParams +from .instance_flavor_detailed import InstanceFlavorDetailed as InstanceFlavorDetailed +from .image_create_from_volume_params import ImageCreateFromVolumeParams as ImageCreateFromVolumeParams diff --git a/src/gcore/types/cloud/instances/flavor_list_params.py b/src/gcore/types/cloud/instances/flavor_list_params.py new file mode 100644 index 00000000..95fd4c92 --- /dev/null +++ b/src/gcore/types/cloud/instances/flavor_list_params.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["FlavorListParams"] + + +class FlavorListParams(TypedDict, total=False): + project_id: int + + region_id: int + + disabled: bool + """Flag for filtering disabled flavors in the region. Defaults to true""" + + exclude_linux: bool + """Set to true to exclude flavors dedicated to linux images. Default False""" + + exclude_windows: bool + """Set to true to exclude flavors dedicated to windows images. Default False""" + + include_prices: bool + """Set to true if the response should include flavor prices""" diff --git a/src/gcore/types/cloud/instances/image_create_from_volume_params.py b/src/gcore/types/cloud/instances/image_create_from_volume_params.py new file mode 100644 index 00000000..52928edb --- /dev/null +++ b/src/gcore/types/cloud/instances/image_create_from_volume_params.py @@ -0,0 +1,51 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ImageCreateFromVolumeParams"] + + +class ImageCreateFromVolumeParams(TypedDict, total=False): + project_id: int + + region_id: int + + name: Required[str] + """Image name""" + + volume_id: Required[str] + """Required if source is volume. Volume id""" + + architecture: Literal["aarch64", "x86_64"] + """Image CPU architecture type: `aarch64`, `x86_64`""" + + hw_firmware_type: Optional[Literal["bios", "uefi"]] + """Specifies the type of firmware with which to boot the guest.""" + + hw_machine_type: Optional[Literal["pc", "q35"]] + """A virtual chipset type.""" + + is_baremetal: bool + """Set to true if the image will be used by bare metal servers. Defaults to false.""" + + os_type: Literal["linux", "windows"] + """The operating system installed on the image.""" + + source: Literal["volume"] + """Image source""" + + ssh_key: Literal["allow", "deny", "required"] + """Whether the image supports SSH key or not""" + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ diff --git a/src/gcore/types/cloud/instances/image_get_params.py b/src/gcore/types/cloud/instances/image_get_params.py new file mode 100644 index 00000000..f9d96463 --- /dev/null +++ b/src/gcore/types/cloud/instances/image_get_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ImageGetParams"] + + +class ImageGetParams(TypedDict, total=False): + project_id: int + + region_id: int + + include_prices: bool + """Show price""" diff --git a/src/gcore/types/cloud/instances/image_list_params.py b/src/gcore/types/cloud/instances/image_list_params.py new file mode 100644 index 00000000..1e1d2903 --- /dev/null +++ b/src/gcore/types/cloud/instances/image_list_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["ImageListParams"] + + +class ImageListParams(TypedDict, total=False): + project_id: int + + region_id: int + + include_prices: bool + """Show price""" + + private: str + """Any value to show private images""" + + tag_key: SequenceNotStr[str] + """Filter by tag keys.""" + + tag_key_value: str + """Filter by tag key-value pairs. Must be a valid JSON string.""" + + visibility: Literal["private", "public", "shared"] + """Image visibility. Globally visible images are public""" diff --git a/src/gcore/types/cloud/instances/image_update_params.py b/src/gcore/types/cloud/instances/image_update_params.py new file mode 100644 index 00000000..d51c715f --- /dev/null +++ b/src/gcore/types/cloud/instances/image_update_params.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +from ..tag_update_map_param import TagUpdateMapParam + +__all__ = ["ImageUpdateParams"] + + +class ImageUpdateParams(TypedDict, total=False): + project_id: int + + region_id: int + + hw_firmware_type: Literal["bios", "uefi"] + """Specifies the type of firmware with which to boot the guest.""" + + hw_machine_type: Literal["pc", "q35"] + """A virtual chipset type.""" + + is_baremetal: bool + """Set to true if the image will be used by bare metal servers.""" + + name: str + """Image display name""" + + os_type: Literal["linux", "windows"] + """The operating system installed on the image.""" + + ssh_key: Literal["allow", "deny", "required"] + """Whether the image supports SSH key or not""" + + tags: TagUpdateMapParam + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ diff --git a/src/gcore/types/cloud/instances/image_upload_params.py b/src/gcore/types/cloud/instances/image_upload_params.py new file mode 100644 index 00000000..a10d83fe --- /dev/null +++ b/src/gcore/types/cloud/instances/image_upload_params.py @@ -0,0 +1,60 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ImageUploadParams"] + + +class ImageUploadParams(TypedDict, total=False): + project_id: int + + region_id: int + + name: Required[str] + """Image name""" + + url: Required[str] + """URL""" + + architecture: Literal["aarch64", "x86_64"] + """Image CPU architecture type: `aarch64`, `x86_64`""" + + cow_format: bool + """ + When True, image cannot be deleted unless all volumes, created from it, are + deleted. + """ + + hw_firmware_type: Optional[Literal["bios", "uefi"]] + """Specifies the type of firmware with which to boot the guest.""" + + hw_machine_type: Optional[Literal["pc", "q35"]] + """A virtual chipset type.""" + + is_baremetal: bool + """Set to true if the image will be used by bare metal servers. Defaults to false.""" + + os_distro: Optional[str] + """OS Distribution, i.e. Debian, CentOS, Ubuntu, CoreOS etc.""" + + os_type: Literal["linux", "windows"] + """The operating system installed on the image.""" + + os_version: Optional[str] + """OS version, i.e. 22.04 (for Ubuntu) or 9.4 for Debian""" + + ssh_key: Literal["allow", "deny", "required"] + """Whether the image supports SSH key or not""" + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ diff --git a/src/gcore/types/cloud/instances/instance_flavor_detailed.py b/src/gcore/types/cloud/instances/instance_flavor_detailed.py new file mode 100644 index 00000000..b1605b03 --- /dev/null +++ b/src/gcore/types/cloud/instances/instance_flavor_detailed.py @@ -0,0 +1,85 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Union, Optional +from typing_extensions import Literal, TypeAlias + +from ...._models import BaseModel + +__all__ = [ + "InstanceFlavorDetailed", + "InstanceFlavorExtendedSerializerWithoutPrice", + "InstanceFlavorExtendedSerializerWithPrice", +] + + +class InstanceFlavorExtendedSerializerWithoutPrice(BaseModel): + """Instances flavor schema without price information""" + + architecture: str + """Flavor architecture type""" + + disabled: bool + """Disabled flavor flag""" + + flavor_id: str + """Flavor ID is the same as name""" + + flavor_name: str + """Flavor name""" + + hardware_description: Dict[str, str] + """Additional hardware description""" + + os_type: str + """Flavor operating system""" + + ram: int + """RAM size in MiB""" + + vcpus: int + """Virtual CPU count""" + + +class InstanceFlavorExtendedSerializerWithPrice(BaseModel): + """Instances flavor schema with price information""" + + architecture: str + """Flavor architecture type""" + + currency_code: Optional[str] = None + """Currency code""" + + disabled: bool + """Disabled flavor flag""" + + flavor_id: str + """Flavor ID is the same as name""" + + flavor_name: str + """Flavor name""" + + hardware_description: Dict[str, str] + """Additional hardware description""" + + os_type: str + """Flavor operating system""" + + price_per_hour: Optional[float] = None + """Price per hour""" + + price_per_month: Optional[float] = None + """Price per month""" + + price_status: Optional[Literal["error", "hide", "show"]] = None + """Price status for the UI""" + + ram: int + """RAM size in MiB""" + + vcpus: int + """Virtual CPU count""" + + +InstanceFlavorDetailed: TypeAlias = Union[ + InstanceFlavorExtendedSerializerWithoutPrice, InstanceFlavorExtendedSerializerWithPrice +] diff --git a/src/gcore/types/cloud/instances/instance_flavor_list.py b/src/gcore/types/cloud/instances/instance_flavor_list.py new file mode 100644 index 00000000..3977e00c --- /dev/null +++ b/src/gcore/types/cloud/instances/instance_flavor_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ...._models import BaseModel +from .instance_flavor_detailed import InstanceFlavorDetailed + +__all__ = ["InstanceFlavorList"] + + +class InstanceFlavorList(BaseModel): + count: int + """Number of objects""" + + results: List[InstanceFlavorDetailed] + """Objects""" diff --git a/src/gcore/types/cloud/instances/interface_attach_params.py b/src/gcore/types/cloud/instances/interface_attach_params.py new file mode 100644 index 00000000..f3a3c26e --- /dev/null +++ b/src/gcore/types/cloud/instances/interface_attach_params.py @@ -0,0 +1,269 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "InterfaceAttachParams", + "NewInterfaceExternalExtendSchemaWithDDOS", + "NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile", + "NewInterfaceExternalExtendSchemaWithDdosddosProfileField", + "NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup", + "NewInterfaceSpecificSubnetSchema", + "NewInterfaceSpecificSubnetSchemaDDOSProfile", + "NewInterfaceSpecificSubnetSchemaDDOSProfileField", + "NewInterfaceSpecificSubnetSchemaSecurityGroup", + "NewInterfaceAnySubnetSchema", + "NewInterfaceAnySubnetSchemaDDOSProfile", + "NewInterfaceAnySubnetSchemaDDOSProfileField", + "NewInterfaceAnySubnetSchemaSecurityGroup", + "NewInterfaceReservedFixedIPSchema", + "NewInterfaceReservedFixedIPSchemaDDOSProfile", + "NewInterfaceReservedFixedIPSchemaDDOSProfileField", + "NewInterfaceReservedFixedIPSchemaSecurityGroup", +] + + +class NewInterfaceExternalExtendSchemaWithDDOS(TypedDict, total=False): + project_id: int + + region_id: int + + ddos_profile: NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile + """Advanced DDoS protection.""" + + interface_name: str + """Interface name""" + + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6 or use dual stack.""" + + port_group: int + """Each group will be added to the separate trunk.""" + + security_groups: Iterable[NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + """List of security group IDs""" + + type: str + """Must be 'external'. Union tag""" + + +class NewInterfaceExternalExtendSchemaWithDdosddosProfileField(TypedDict, total=False): + base_field: Optional[int] + """ID of DDoS profile field""" + + field_name: Optional[str] + """Name of DDoS profile field""" + + field_value: object + """Complex value. Only one of 'value' or 'field_value' must be specified.""" + + value: Optional[str] + """Basic type value. Only one of 'value' or 'field_value' must be specified.""" + + +class NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile(TypedDict, total=False): + """Advanced DDoS protection.""" + + profile_template: Required[int] + """DDoS profile template ID.""" + + fields: Iterable[NewInterfaceExternalExtendSchemaWithDdosddosProfileField] + """Protection parameters.""" + + profile_template_name: str + """DDoS profile template name.""" + + +class NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup(TypedDict, total=False): + """MandatoryIdSchema schema""" + + id: Required[str] + """Resource ID""" + + +class NewInterfaceSpecificSubnetSchema(TypedDict, total=False): + project_id: int + + region_id: int + + subnet_id: Required[str] + """Port will get an IP address from this subnet""" + + ddos_profile: NewInterfaceSpecificSubnetSchemaDDOSProfile + """Advanced DDoS protection.""" + + interface_name: str + """Interface name""" + + port_group: int + """Each group will be added to the separate trunk.""" + + security_groups: Iterable[NewInterfaceSpecificSubnetSchemaSecurityGroup] + """List of security group IDs""" + + type: str + """Must be 'subnet'""" + + +class NewInterfaceSpecificSubnetSchemaDDOSProfileField(TypedDict, total=False): + base_field: Optional[int] + """ID of DDoS profile field""" + + field_name: Optional[str] + """Name of DDoS profile field""" + + field_value: object + """Complex value. Only one of 'value' or 'field_value' must be specified.""" + + value: Optional[str] + """Basic type value. Only one of 'value' or 'field_value' must be specified.""" + + +class NewInterfaceSpecificSubnetSchemaDDOSProfile(TypedDict, total=False): + """Advanced DDoS protection.""" + + profile_template: Required[int] + """DDoS profile template ID.""" + + fields: Iterable[NewInterfaceSpecificSubnetSchemaDDOSProfileField] + """Protection parameters.""" + + profile_template_name: str + """DDoS profile template name.""" + + +class NewInterfaceSpecificSubnetSchemaSecurityGroup(TypedDict, total=False): + """MandatoryIdSchema schema""" + + id: Required[str] + """Resource ID""" + + +class NewInterfaceAnySubnetSchema(TypedDict, total=False): + project_id: int + + region_id: int + + network_id: Required[str] + """Port will get an IP address in this network subnet""" + + ddos_profile: NewInterfaceAnySubnetSchemaDDOSProfile + """Advanced DDoS protection.""" + + interface_name: str + """Interface name""" + + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6 or use dual stack.""" + + port_group: int + """Each group will be added to the separate trunk.""" + + security_groups: Iterable[NewInterfaceAnySubnetSchemaSecurityGroup] + """List of security group IDs""" + + type: str + """Must be 'any_subnet'""" + + +class NewInterfaceAnySubnetSchemaDDOSProfileField(TypedDict, total=False): + base_field: Optional[int] + """ID of DDoS profile field""" + + field_name: Optional[str] + """Name of DDoS profile field""" + + field_value: object + """Complex value. Only one of 'value' or 'field_value' must be specified.""" + + value: Optional[str] + """Basic type value. Only one of 'value' or 'field_value' must be specified.""" + + +class NewInterfaceAnySubnetSchemaDDOSProfile(TypedDict, total=False): + """Advanced DDoS protection.""" + + profile_template: Required[int] + """DDoS profile template ID.""" + + fields: Iterable[NewInterfaceAnySubnetSchemaDDOSProfileField] + """Protection parameters.""" + + profile_template_name: str + """DDoS profile template name.""" + + +class NewInterfaceAnySubnetSchemaSecurityGroup(TypedDict, total=False): + """MandatoryIdSchema schema""" + + id: Required[str] + """Resource ID""" + + +class NewInterfaceReservedFixedIPSchema(TypedDict, total=False): + project_id: int + + region_id: int + + port_id: Required[str] + """Port ID""" + + ddos_profile: NewInterfaceReservedFixedIPSchemaDDOSProfile + """Advanced DDoS protection.""" + + interface_name: str + """Interface name""" + + port_group: int + """Each group will be added to the separate trunk.""" + + security_groups: Iterable[NewInterfaceReservedFixedIPSchemaSecurityGroup] + """List of security group IDs""" + + type: str + """Must be 'reserved_fixed_ip'. Union tag""" + + +class NewInterfaceReservedFixedIPSchemaDDOSProfileField(TypedDict, total=False): + base_field: Optional[int] + """ID of DDoS profile field""" + + field_name: Optional[str] + """Name of DDoS profile field""" + + field_value: object + """Complex value. Only one of 'value' or 'field_value' must be specified.""" + + value: Optional[str] + """Basic type value. Only one of 'value' or 'field_value' must be specified.""" + + +class NewInterfaceReservedFixedIPSchemaDDOSProfile(TypedDict, total=False): + """Advanced DDoS protection.""" + + profile_template: Required[int] + """DDoS profile template ID.""" + + fields: Iterable[NewInterfaceReservedFixedIPSchemaDDOSProfileField] + """Protection parameters.""" + + profile_template_name: str + """DDoS profile template name.""" + + +class NewInterfaceReservedFixedIPSchemaSecurityGroup(TypedDict, total=False): + """MandatoryIdSchema schema""" + + id: Required[str] + """Resource ID""" + + +InterfaceAttachParams: TypeAlias = Union[ + NewInterfaceExternalExtendSchemaWithDDOS, + NewInterfaceSpecificSubnetSchema, + NewInterfaceAnySubnetSchema, + NewInterfaceReservedFixedIPSchema, +] diff --git a/src/gcore/types/cloud/instances/interface_detach_params.py b/src/gcore/types/cloud/instances/interface_detach_params.py new file mode 100644 index 00000000..5f092a84 --- /dev/null +++ b/src/gcore/types/cloud/instances/interface_detach_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["InterfaceDetachParams"] + + +class InterfaceDetachParams(TypedDict, total=False): + project_id: int + + region_id: int + + ip_address: Required[str] + """IP address""" + + port_id: Required[str] + """ID of the port""" diff --git a/src/gcore/types/cloud/instances/metric_list_params.py b/src/gcore/types/cloud/instances/metric_list_params.py new file mode 100644 index 00000000..13be263e --- /dev/null +++ b/src/gcore/types/cloud/instances/metric_list_params.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from ..instance_metrics_time_unit import InstanceMetricsTimeUnit + +__all__ = ["MetricListParams"] + + +class MetricListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + time_interval: Required[int] + """Time interval.""" + + time_unit: Required[InstanceMetricsTimeUnit] + """Time interval unit.""" diff --git a/src/gcore/types/cloud/instances/metrics.py b/src/gcore/types/cloud/instances/metrics.py new file mode 100644 index 00000000..f457b606 --- /dev/null +++ b/src/gcore/types/cloud/instances/metrics.py @@ -0,0 +1,56 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel + +__all__ = ["Metrics", "Disk"] + + +class Disk(BaseModel): + """Disk metrics item""" + + disk_bps_read: Optional[float] = FieldInfo(alias="disk_Bps_read", default=None) + """Disk read, Bytes per second""" + + disk_bps_write: Optional[float] = FieldInfo(alias="disk_Bps_write", default=None) + """Disk write, Bytes per second""" + + disk_iops_read: Optional[float] = None + """Disk read, iops""" + + disk_iops_write: Optional[float] = None + """Disk write, iops""" + + disk_name: Optional[str] = None + """Disk attached slot name""" + + +class Metrics(BaseModel): + """Instance metrics item""" + + time: str + """Timestamp""" + + cpu_util: Optional[float] = None + """CPU utilization, % (max 100% for multi-core)""" + + disks: Optional[List[Disk]] = None + """Disks metrics for each of the disks attached""" + + memory_util: Optional[float] = None + """RAM utilization, %""" + + network_bps_egress: Optional[float] = FieldInfo(alias="network_Bps_egress", default=None) + """Network out, bytes per second""" + + network_bps_ingress: Optional[float] = FieldInfo(alias="network_Bps_ingress", default=None) + """Network in, bytes per second""" + + network_pps_egress: Optional[float] = None + """Network out, packets per second""" + + network_pps_ingress: Optional[float] = None + """Network in, packets per second""" diff --git a/src/gcore/types/cloud/instances/metrics_list.py b/src/gcore/types/cloud/instances/metrics_list.py new file mode 100644 index 00000000..d898b4a6 --- /dev/null +++ b/src/gcore/types/cloud/instances/metrics_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from .metrics import Metrics +from ...._models import BaseModel + +__all__ = ["MetricsList"] + + +class MetricsList(BaseModel): + count: int + """Number of objects""" + + results: List[Metrics] + """Objects""" diff --git a/src/gcore/types/cloud/interface_ip_family.py b/src/gcore/types/cloud/interface_ip_family.py new file mode 100644 index 00000000..78a0696b --- /dev/null +++ b/src/gcore/types/cloud/interface_ip_family.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["InterfaceIPFamily"] + +InterfaceIPFamily: TypeAlias = Literal["dual", "ipv4", "ipv6"] diff --git a/src/gcore/types/cloud/ip_assignment.py b/src/gcore/types/cloud/ip_assignment.py new file mode 100644 index 00000000..49dcc87c --- /dev/null +++ b/src/gcore/types/cloud/ip_assignment.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["IPAssignment"] + + +class IPAssignment(BaseModel): + ip_address: str + """IP address""" + + subnet_id: str + """ID of the subnet that allocated the IP""" diff --git a/src/gcore/types/cloud/ip_ranges.py b/src/gcore/types/cloud/ip_ranges.py new file mode 100644 index 00000000..5c983ebe --- /dev/null +++ b/src/gcore/types/cloud/ip_ranges.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel + +__all__ = ["IPRanges"] + + +class IPRanges(BaseModel): + ranges: List[str] + """IP ranges list""" diff --git a/src/gcore/types/cloud/ip_version.py b/src/gcore/types/cloud/ip_version.py new file mode 100644 index 00000000..be9bb0fc --- /dev/null +++ b/src/gcore/types/cloud/ip_version.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["IPVersion"] + +IPVersion: TypeAlias = Literal[4, 6] diff --git a/src/gcore/types/cloud/k8s/__init__.py b/src/gcore/types/cloud/k8s/__init__.py new file mode 100644 index 00000000..0eed39f3 --- /dev/null +++ b/src/gcore/types/cloud/k8s/__init__.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .k8s_cluster import K8SCluster as K8SCluster +from .k8s_cluster_list import K8SClusterList as K8SClusterList +from .flavor_list_params import FlavorListParams as FlavorListParams +from .cluster_create_params import ClusterCreateParams as ClusterCreateParams +from .cluster_delete_params import ClusterDeleteParams as ClusterDeleteParams +from .cluster_update_params import ClusterUpdateParams as ClusterUpdateParams +from .cluster_upgrade_params import ClusterUpgradeParams as ClusterUpgradeParams +from .k8s_cluster_kubeconfig import K8SClusterKubeconfig as K8SClusterKubeconfig +from .k8s_cluster_certificate import K8SClusterCertificate as K8SClusterCertificate diff --git a/src/gcore/types/cloud/k8s/cluster_create_params.py b/src/gcore/types/cloud/k8s/cluster_create_params.py new file mode 100644 index 00000000..6888e441 --- /dev/null +++ b/src/gcore/types/cloud/k8s/cluster_create_params.py @@ -0,0 +1,365 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr +from ..laas_index_retention_policy_param import LaasIndexRetentionPolicyParam + +__all__ = [ + "ClusterCreateParams", + "Pool", + "AddOns", + "AddOnsSlurm", + "Authentication", + "AuthenticationOidc", + "Cni", + "CniCilium", + "Csi", + "CsiNfs", + "DDOSProfile", + "DDOSProfileField", + "Logging", +] + + +class ClusterCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + keypair: Required[str] + """The keypair of the cluster""" + + name: Required[str] + """The name of the cluster""" + + pools: Required[Iterable[Pool]] + """The pools of the cluster""" + + version: Required[str] + """The version of the k8s cluster""" + + add_ons: AddOns + """Cluster add-ons configuration""" + + authentication: Optional[Authentication] + """Authentication settings""" + + autoscaler_config: Optional[Dict[str, str]] + """Cluster autoscaler configuration. + + It allows you to override the default cluster-autoscaler parameters provided by + the platform with your preferred values. + + Supported parameters (in alphabetical order): + + - balance-similar-node-groups (boolean: true/false) - Detect similar node groups + and balance the number of nodes between them. + - expander (string: random, most-pods, least-waste, price, priority, grpc) - + Type of node group expander to be used in scale up. Specifying multiple values + separated by commas will call the expanders in succession until there is only + one option remaining. + - expendable-pods-priority-cutoff (float) - Pods with priority below cutoff will + be expendable. They can be killed without any consideration during scale down + and they don't cause scale up. Pods with null priority (PodPriority disabled) + are non expendable. + - ignore-daemonsets-utilization (boolean: true/false) - Should CA ignore + DaemonSet pods when calculating resource utilization for scaling down. + - max-empty-bulk-delete (integer) - Maximum number of empty nodes that can be + deleted at the same time. + - max-graceful-termination-sec (integer) - Maximum number of seconds CA waits + for pod termination when trying to scale down a node. + - max-node-provision-time (duration: e.g., '15m') - The default maximum time CA + waits for node to be provisioned - the value can be overridden per node group. + - max-total-unready-percentage (float) - Maximum percentage of unready nodes in + the cluster. After this is exceeded, CA halts operations. + - new-pod-scale-up-delay (duration: e.g., '10s') - Pods less than this old will + not be considered for scale-up. Can be increased for individual pods through + annotation. + - ok-total-unready-count (integer) - Number of allowed unready nodes, + irrespective of max-total-unready-percentage. + - scale-down-delay-after-add (duration: e.g., '10m') - How long after scale up + that scale down evaluation resumes. + - scale-down-delay-after-delete (duration: e.g., '10s') - How long after node + deletion that scale down evaluation resumes. + - scale-down-delay-after-failure (duration: e.g., '3m') - How long after scale + down failure that scale down evaluation resumes. + - scale-down-enabled (boolean: true/false) - Should CA scale down the cluster. + - scale-down-unneeded-time (duration: e.g., '10m') - How long a node should be + unneeded before it is eligible for scale down. + - scale-down-unready-time (duration: e.g., '20m') - How long an unready node + should be unneeded before it is eligible for scale down. + - scale-down-utilization-threshold (float) - The maximum value between the sum + of cpu requests and sum of memory requests of all pods running on the node + divided by node's corresponding allocatable resource, below which a node can + be considered for scale down. + - scan-interval (duration: e.g., '10s') - How often cluster is reevaluated for + scale up or down. + - skip-nodes-with-custom-controller-pods (boolean: true/false) - If true cluster + autoscaler will never delete nodes with pods owned by custom controllers. + - skip-nodes-with-local-storage (boolean: true/false) - If true cluster + autoscaler will never delete nodes with pods with local storage, e.g. EmptyDir + or HostPath. + - skip-nodes-with-system-pods (boolean: true/false) - If true cluster autoscaler + will never delete nodes with pods from kube-system (except for DaemonSet or + mirror pods). + """ + + cni: Optional[Cni] + """Cluster CNI settings""" + + csi: Csi + """Container Storage Interface (CSI) driver settings""" + + ddos_profile: Optional[DDOSProfile] + """Advanced DDoS Protection profile""" + + fixed_network: Optional[str] + """The network of the cluster""" + + fixed_subnet: Optional[str] + """The subnet of the cluster""" + + is_ipv6: Optional[bool] + """Enable public v6 address""" + + logging: Optional[Logging] + """Logging configuration""" + + pods_ip_pool: Optional[str] + """The IP pool for the pods""" + + pods_ipv6_pool: Optional[str] + """The IPv6 pool for the pods""" + + services_ip_pool: Optional[str] + """The IP pool for the services""" + + services_ipv6_pool: Optional[str] + """The IPv6 pool for the services""" + + +class Pool(TypedDict, total=False): + flavor_id: Required[str] + """Flavor ID""" + + min_node_count: Required[int] + """Minimum node count""" + + name: Required[str] + """Pool's name""" + + auto_healing_enabled: Optional[bool] + """Enable auto healing""" + + boot_volume_size: Optional[int] + """Boot volume size""" + + boot_volume_type: Optional[Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"]] + """Boot volume type""" + + crio_config: Optional[Dict[str, str]] + """Cri-o configuration for pool nodes""" + + is_public_ipv4: Optional[bool] + """Enable public v4 address""" + + kubelet_config: Optional[Dict[str, str]] + """Kubelet configuration for pool nodes""" + + labels: Optional[Dict[str, str]] + """Labels applied to the cluster pool""" + + max_node_count: Optional[int] + """Maximum node count""" + + servergroup_policy: Optional[Literal["affinity", "anti-affinity", "soft-anti-affinity"]] + """Server group policy: anti-affinity, soft-anti-affinity or affinity""" + + taints: Optional[Dict[str, str]] + """Taints applied to the cluster pool""" + + +class AddOnsSlurm(TypedDict, total=False): + """Slurm add-on configuration""" + + enabled: Required[Literal[True]] + """The Slurm add-on will be enabled in the cluster. + + This add-on is only supported in clusters running Kubernetes v1.31 and v1.32 + with at least 1 GPU cluster pool and VAST NFS support enabled. + """ + + file_share_id: Required[str] + """ID of a VAST file share to be used as Slurm storage. + + The Slurm add-on will create separate Persistent Volume Claims for different + purposes (controller spool, worker spool, jail) on that file share. + + The file share must have `root_squash` disabled, while `path_length` and + `allowed_characters` settings must be set to `NPL`. + """ + + ssh_key_ids: Required[SequenceNotStr[str]] + """IDs of SSH keys to authorize for SSH connection to Slurm login nodes.""" + + worker_count: Required[int] + """Size of the worker pool, i.e. the number of Slurm worker nodes. + + Each Slurm worker node will be backed by a Pod scheduled on one of cluster's GPU + nodes. + + Note: Downscaling (reducing worker count) is not supported. + """ + + +class AddOns(TypedDict, total=False): + """Cluster add-ons configuration""" + + slurm: AddOnsSlurm + """Slurm add-on configuration""" + + +class AuthenticationOidc(TypedDict, total=False): + """OIDC authentication settings""" + + client_id: Optional[str] + """Client ID""" + + groups_claim: Optional[str] + """JWT claim to use as the user's group""" + + groups_prefix: Optional[str] + """Prefix prepended to group claims""" + + issuer_url: Optional[str] + """Issuer URL""" + + required_claims: Optional[Dict[str, str]] + """Key-value pairs that describe required claims in the token""" + + signing_algs: Optional[ + List[Literal["ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "RS256", "RS384", "RS512"]] + ] + """Accepted signing algorithms""" + + username_claim: Optional[str] + """JWT claim to use as the user name""" + + username_prefix: Optional[str] + """Prefix prepended to username claims to prevent clashes""" + + +class Authentication(TypedDict, total=False): + """Authentication settings""" + + oidc: Optional[AuthenticationOidc] + """OIDC authentication settings""" + + +class CniCilium(TypedDict, total=False): + """Cilium settings""" + + encryption: bool + """Wireguard encryption""" + + hubble_relay: bool + """Hubble Relay""" + + hubble_ui: bool + """Hubble UI""" + + lb_acceleration: bool + """LoadBalancer acceleration""" + + lb_mode: Literal["dsr", "hybrid", "snat"] + """LoadBalancer mode""" + + mask_size: int + """Mask size for IPv4""" + + mask_size_v6: int + """Mask size for IPv6""" + + routing_mode: Literal["native", "tunnel"] + """Routing mode""" + + tunnel: Literal["", "geneve", "vxlan"] + """CNI provider""" + + +class Cni(TypedDict, total=False): + """Cluster CNI settings""" + + cilium: Optional[CniCilium] + """Cilium settings""" + + provider: Literal["calico", "cilium"] + """CNI provider""" + + +class CsiNfs(TypedDict, total=False): + """NFS CSI driver settings""" + + vast_enabled: bool + """Enable or disable VAST NFS integration. + + The default value is `false`. When set to `true`, a dedicated StorageClass will + be created in the cluster for each VAST NFS file share defined in the cloud. All + file shares created prior to cluster creation will be available immediately, + while those created afterward may take a few minutes for to appear. + """ + + +class Csi(TypedDict, total=False): + """Container Storage Interface (CSI) driver settings""" + + nfs: CsiNfs + """NFS CSI driver settings""" + + +class DDOSProfileField(TypedDict, total=False): + base_field: Required[int] + + field_value: object + """Complex value. Only one of 'value' or 'field_value' must be specified""" + + value: Optional[str] + """Basic value. Only one of 'value' or 'field_value' must be specified""" + + +class DDOSProfile(TypedDict, total=False): + """Advanced DDoS Protection profile""" + + enabled: Required[bool] + """Enable advanced DDoS protection""" + + fields: Iterable[DDOSProfileField] + """DDoS profile parameters""" + + profile_template: Optional[int] + """DDoS profile template ID""" + + profile_template_name: Optional[str] + """DDoS profile template name""" + + +class Logging(TypedDict, total=False): + """Logging configuration""" + + destination_region_id: Optional[int] + """Destination region id to which the logs will be written""" + + enabled: bool + """Enable/disable forwarding logs to LaaS""" + + retention_policy: Optional[LaasIndexRetentionPolicyParam] + """The logs retention policy""" + + topic_name: Optional[str] + """The topic name to which the logs will be written""" diff --git a/src/gcore/types/cloud/k8s/cluster_delete_params.py b/src/gcore/types/cloud/k8s/cluster_delete_params.py new file mode 100644 index 00000000..e1b433ea --- /dev/null +++ b/src/gcore/types/cloud/k8s/cluster_delete_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ClusterDeleteParams"] + + +class ClusterDeleteParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + volumes: str + """Comma separated list of volume IDs to be deleted with the cluster""" diff --git a/src/gcore/types/cloud/k8s/cluster_update_params.py b/src/gcore/types/cloud/k8s/cluster_update_params.py new file mode 100644 index 00000000..911a71e8 --- /dev/null +++ b/src/gcore/types/cloud/k8s/cluster_update_params.py @@ -0,0 +1,275 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ...._types import SequenceNotStr +from ..laas_index_retention_policy_param import LaasIndexRetentionPolicyParam + +__all__ = [ + "ClusterUpdateParams", + "AddOns", + "AddOnsSlurm", + "AddOnsSlurmK8SClusterSlurmAddonEnableV2Serializer", + "AddOnsSlurmK8SClusterSlurmAddonDisableV2Serializer", + "Authentication", + "AuthenticationOidc", + "Cni", + "CniCilium", + "DDOSProfile", + "DDOSProfileField", + "Logging", +] + + +class ClusterUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + add_ons: AddOns + """Cluster add-ons configuration""" + + authentication: Optional[Authentication] + """Authentication settings""" + + autoscaler_config: Optional[Dict[str, str]] + """Cluster autoscaler configuration. + + It allows you to override the default cluster-autoscaler parameters provided by + the platform with your preferred values. + + Supported parameters (in alphabetical order): + + - balance-similar-node-groups (boolean: true/false) - Detect similar node groups + and balance the number of nodes between them. + - expander (string: random, most-pods, least-waste, price, priority, grpc) - + Type of node group expander to be used in scale up. Specifying multiple values + separated by commas will call the expanders in succession until there is only + one option remaining. + - expendable-pods-priority-cutoff (float) - Pods with priority below cutoff will + be expendable. They can be killed without any consideration during scale down + and they don't cause scale up. Pods with null priority (PodPriority disabled) + are non expendable. + - ignore-daemonsets-utilization (boolean: true/false) - Should CA ignore + DaemonSet pods when calculating resource utilization for scaling down. + - max-empty-bulk-delete (integer) - Maximum number of empty nodes that can be + deleted at the same time. + - max-graceful-termination-sec (integer) - Maximum number of seconds CA waits + for pod termination when trying to scale down a node. + - max-node-provision-time (duration: e.g., '15m') - The default maximum time CA + waits for node to be provisioned - the value can be overridden per node group. + - max-total-unready-percentage (float) - Maximum percentage of unready nodes in + the cluster. After this is exceeded, CA halts operations. + - new-pod-scale-up-delay (duration: e.g., '10s') - Pods less than this old will + not be considered for scale-up. Can be increased for individual pods through + annotation. + - ok-total-unready-count (integer) - Number of allowed unready nodes, + irrespective of max-total-unready-percentage. + - scale-down-delay-after-add (duration: e.g., '10m') - How long after scale up + that scale down evaluation resumes. + - scale-down-delay-after-delete (duration: e.g., '10s') - How long after node + deletion that scale down evaluation resumes. + - scale-down-delay-after-failure (duration: e.g., '3m') - How long after scale + down failure that scale down evaluation resumes. + - scale-down-enabled (boolean: true/false) - Should CA scale down the cluster. + - scale-down-unneeded-time (duration: e.g., '10m') - How long a node should be + unneeded before it is eligible for scale down. + - scale-down-unready-time (duration: e.g., '20m') - How long an unready node + should be unneeded before it is eligible for scale down. + - scale-down-utilization-threshold (float) - The maximum value between the sum + of cpu requests and sum of memory requests of all pods running on the node + divided by node's corresponding allocatable resource, below which a node can + be considered for scale down. + - scan-interval (duration: e.g., '10s') - How often cluster is reevaluated for + scale up or down. + - skip-nodes-with-custom-controller-pods (boolean: true/false) - If true cluster + autoscaler will never delete nodes with pods owned by custom controllers. + - skip-nodes-with-local-storage (boolean: true/false) - If true cluster + autoscaler will never delete nodes with pods with local storage, e.g. EmptyDir + or HostPath. + - skip-nodes-with-system-pods (boolean: true/false) - If true cluster autoscaler + will never delete nodes with pods from kube-system (except for DaemonSet or + mirror pods). + """ + + cni: Optional[Cni] + """Cluster CNI settings""" + + ddos_profile: Optional[DDOSProfile] + """Advanced DDoS Protection profile""" + + logging: Optional[Logging] + """Logging configuration""" + + +class AddOnsSlurmK8SClusterSlurmAddonEnableV2Serializer(TypedDict, total=False): + enabled: Required[Literal[True]] + """The Slurm add-on will be enabled in the cluster. + + This add-on is only supported in clusters running Kubernetes v1.31 and v1.32 + with at least 1 GPU cluster pool and VAST NFS support enabled. + """ + + file_share_id: Required[str] + """ID of a VAST file share to be used as Slurm storage. + + The Slurm add-on will create separate Persistent Volume Claims for different + purposes (controller spool, worker spool, jail) on that file share. + + The file share must have `root_squash` disabled, while `path_length` and + `allowed_characters` settings must be set to `NPL`. + """ + + ssh_key_ids: Required[SequenceNotStr[str]] + """IDs of SSH keys to authorize for SSH connection to Slurm login nodes.""" + + worker_count: Required[int] + """Size of the worker pool, i.e. the number of Slurm worker nodes. + + Each Slurm worker node will be backed by a Pod scheduled on one of cluster's GPU + nodes. + + Note: Downscaling (reducing worker count) is not supported. + """ + + +class AddOnsSlurmK8SClusterSlurmAddonDisableV2Serializer(TypedDict, total=False): + enabled: Required[Literal[False]] + """The Slurm add-on will be disabled in the cluster.""" + + +AddOnsSlurm: TypeAlias = Union[ + AddOnsSlurmK8SClusterSlurmAddonEnableV2Serializer, AddOnsSlurmK8SClusterSlurmAddonDisableV2Serializer +] + + +class AddOns(TypedDict, total=False): + """Cluster add-ons configuration""" + + slurm: AddOnsSlurm + """Slurm add-on configuration""" + + +class AuthenticationOidc(TypedDict, total=False): + """OIDC authentication settings""" + + client_id: Optional[str] + """Client ID""" + + groups_claim: Optional[str] + """JWT claim to use as the user's group""" + + groups_prefix: Optional[str] + """Prefix prepended to group claims""" + + issuer_url: Optional[str] + """Issuer URL""" + + required_claims: Optional[Dict[str, str]] + """Key-value pairs that describe required claims in the token""" + + signing_algs: Optional[ + List[Literal["ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "RS256", "RS384", "RS512"]] + ] + """Accepted signing algorithms""" + + username_claim: Optional[str] + """JWT claim to use as the user name""" + + username_prefix: Optional[str] + """Prefix prepended to username claims to prevent clashes""" + + +class Authentication(TypedDict, total=False): + """Authentication settings""" + + oidc: Optional[AuthenticationOidc] + """OIDC authentication settings""" + + +class CniCilium(TypedDict, total=False): + """Cilium settings""" + + encryption: bool + """Wireguard encryption""" + + hubble_relay: bool + """Hubble Relay""" + + hubble_ui: bool + """Hubble UI""" + + lb_acceleration: bool + """LoadBalancer acceleration""" + + lb_mode: Literal["dsr", "hybrid", "snat"] + """LoadBalancer mode""" + + mask_size: int + """Mask size for IPv4""" + + mask_size_v6: int + """Mask size for IPv6""" + + routing_mode: Literal["native", "tunnel"] + """Routing mode""" + + tunnel: Literal["", "geneve", "vxlan"] + """CNI provider""" + + +class Cni(TypedDict, total=False): + """Cluster CNI settings""" + + cilium: Optional[CniCilium] + """Cilium settings""" + + provider: Literal["calico", "cilium"] + """CNI provider""" + + +class DDOSProfileField(TypedDict, total=False): + base_field: Required[int] + + field_value: object + """Complex value. Only one of 'value' or 'field_value' must be specified""" + + value: Optional[str] + """Basic value. Only one of 'value' or 'field_value' must be specified""" + + +class DDOSProfile(TypedDict, total=False): + """Advanced DDoS Protection profile""" + + enabled: Required[bool] + """Enable advanced DDoS protection""" + + fields: Iterable[DDOSProfileField] + """DDoS profile parameters""" + + profile_template: Optional[int] + """DDoS profile template ID""" + + profile_template_name: Optional[str] + """DDoS profile template name""" + + +class Logging(TypedDict, total=False): + """Logging configuration""" + + destination_region_id: Optional[int] + """Destination region id to which the logs will be written""" + + enabled: bool + """Enable/disable forwarding logs to LaaS""" + + retention_policy: Optional[LaasIndexRetentionPolicyParam] + """The logs retention policy""" + + topic_name: Optional[str] + """The topic name to which the logs will be written""" diff --git a/src/gcore/types/cloud/k8s/cluster_upgrade_params.py b/src/gcore/types/cloud/k8s/cluster_upgrade_params.py new file mode 100644 index 00000000..dd92d0ac --- /dev/null +++ b/src/gcore/types/cloud/k8s/cluster_upgrade_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ClusterUpgradeParams"] + + +class ClusterUpgradeParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + version: Required[str] + """Target k8s cluster version""" diff --git a/src/gcore/types/cloud/k8s/clusters/__init__.py b/src/gcore/types/cloud/k8s/clusters/__init__.py new file mode 100644 index 00000000..c8c5c859 --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/__init__.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .k8s_cluster_pool import K8SClusterPool as K8SClusterPool +from .node_list_params import NodeListParams as NodeListParams +from .pool_create_params import PoolCreateParams as PoolCreateParams +from .pool_resize_params import PoolResizeParams as PoolResizeParams +from .pool_update_params import PoolUpdateParams as PoolUpdateParams +from .k8s_cluster_pool_list import K8SClusterPoolList as K8SClusterPoolList +from .k8s_cluster_pool_quota import K8SClusterPoolQuota as K8SClusterPoolQuota +from .pool_check_quota_params import PoolCheckQuotaParams as PoolCheckQuotaParams diff --git a/src/gcore/types/cloud/k8s/clusters/k8s_cluster_pool.py b/src/gcore/types/cloud/k8s/clusters/k8s_cluster_pool.py new file mode 100644 index 00000000..415b314c --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/k8s_cluster_pool.py @@ -0,0 +1,66 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional + +from ....._models import BaseModel + +__all__ = ["K8SClusterPool"] + + +class K8SClusterPool(BaseModel): + id: str + """UUID of the cluster pool""" + + auto_healing_enabled: bool + """Indicates the status of auto healing""" + + boot_volume_size: int + """Size of the boot volume""" + + boot_volume_type: str + """Type of the boot volume""" + + created_at: str + """Date of function creation""" + + crio_config: Dict[str, str] + """Crio configuration for pool nodes""" + + flavor_id: str + """ID of the cluster pool flavor""" + + is_public_ipv4: bool + """Indicates if the pool is public""" + + kubelet_config: Dict[str, str] + """Kubelet configuration for pool nodes""" + + labels: Dict[str, str] + """Labels applied to the cluster pool""" + + max_node_count: int + """Maximum node count in the cluster pool""" + + min_node_count: int + """Minimum node count in the cluster pool""" + + name: str + """Name of the cluster pool""" + + node_count: int + """Node count in the cluster pool""" + + status: str + """Status of the cluster pool""" + + taints: Dict[str, str] + """Taints applied to the cluster pool""" + + servergroup_id: Optional[str] = None + """Server group ID""" + + servergroup_name: Optional[str] = None + """Server group name""" + + servergroup_policy: Optional[str] = None + """Anti-affinity, affinity or soft-anti-affinity server group policy""" diff --git a/src/gcore/types/cloud/k8s/clusters/k8s_cluster_pool_list.py b/src/gcore/types/cloud/k8s/clusters/k8s_cluster_pool_list.py new file mode 100644 index 00000000..23f3943a --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/k8s_cluster_pool_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ....._models import BaseModel +from .k8s_cluster_pool import K8SClusterPool + +__all__ = ["K8SClusterPoolList"] + + +class K8SClusterPoolList(BaseModel): + count: int + """Number of objects""" + + results: List[K8SClusterPool] + """Objects""" diff --git a/src/gcore/types/cloud/k8s/clusters/k8s_cluster_pool_quota.py b/src/gcore/types/cloud/k8s/clusters/k8s_cluster_pool_quota.py new file mode 100644 index 00000000..f7c178db --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/k8s_cluster_pool_quota.py @@ -0,0 +1,204 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ....._models import BaseModel + +__all__ = ["K8SClusterPoolQuota"] + + +class K8SClusterPoolQuota(BaseModel): + """Response schema for K8s cluster quota check. + + Returns quota fields that are exceeded. Fields are only included when + regional limits would be violated. Empty response means no quotas exceeded. + """ + + baremetal_gpu_a100_count_limit: Optional[int] = None + """Bare metal A100 GPU server count limit""" + + baremetal_gpu_a100_count_requested: Optional[int] = None + """Bare metal A100 GPU server count requested""" + + baremetal_gpu_a100_count_usage: Optional[int] = None + """Bare metal A100 GPU server count usage""" + + baremetal_gpu_h100_count_limit: Optional[int] = None + """Bare metal H100 GPU server count limit""" + + baremetal_gpu_h100_count_requested: Optional[int] = None + """Bare metal H100 GPU server count requested""" + + baremetal_gpu_h100_count_usage: Optional[int] = None + """Bare metal H100 GPU server count usage""" + + baremetal_gpu_h200_count_limit: Optional[int] = None + """Bare metal H200 GPU server count limit""" + + baremetal_gpu_h200_count_requested: Optional[int] = None + """Bare metal H200 GPU server count requested""" + + baremetal_gpu_h200_count_usage: Optional[int] = None + """Bare metal H200 GPU server count usage""" + + baremetal_gpu_l40s_count_limit: Optional[int] = None + """Bare metal L40S GPU server count limit""" + + baremetal_gpu_l40s_count_requested: Optional[int] = None + """Bare metal L40S GPU server count requested""" + + baremetal_gpu_l40s_count_usage: Optional[int] = None + """Bare metal L40S GPU server count usage""" + + baremetal_hf_count_limit: Optional[int] = None + """High-frequency bare metal servers count limit""" + + baremetal_hf_count_requested: Optional[int] = None + """High-frequency bare metal servers count requested""" + + baremetal_hf_count_usage: Optional[int] = None + """High-frequency bare metal servers count usage""" + + cluster_count_limit: Optional[int] = None + """K8s clusters count limit""" + + cluster_count_requested: Optional[int] = None + """K8s clusters count requested""" + + cluster_count_usage: Optional[int] = None + """K8s clusters count usage""" + + cpu_count_limit: Optional[int] = None + """vCPU Count limit""" + + cpu_count_requested: Optional[int] = None + """vCPU Count requested""" + + cpu_count_usage: Optional[int] = None + """vCPU Count usage""" + + firewall_count_limit: Optional[int] = None + """Firewalls Count limit""" + + firewall_count_requested: Optional[int] = None + """Firewalls Count requested""" + + firewall_count_usage: Optional[int] = None + """Firewalls Count usage""" + + floating_count_limit: Optional[int] = None + """Floating IP Count limit""" + + floating_count_requested: Optional[int] = None + """Floating IP Count requested""" + + floating_count_usage: Optional[int] = None + """Floating IP Count usage""" + + gpu_count_limit: Optional[int] = None + """GPU Count limit""" + + gpu_count_requested: Optional[int] = None + """GPU Count requested""" + + gpu_count_usage: Optional[int] = None + """GPU Count usage""" + + gpu_virtual_a100_count_limit: Optional[int] = None + """Virtual A100 GPU card count limit""" + + gpu_virtual_a100_count_requested: Optional[int] = None + """Virtual A100 GPU card count requested""" + + gpu_virtual_a100_count_usage: Optional[int] = None + """Virtual A100 GPU card count usage""" + + gpu_virtual_h100_count_limit: Optional[int] = None + """Virtual H100 GPU card count limit""" + + gpu_virtual_h100_count_requested: Optional[int] = None + """Virtual H100 GPU card count requested""" + + gpu_virtual_h100_count_usage: Optional[int] = None + """Virtual H100 GPU card count usage""" + + gpu_virtual_h200_count_limit: Optional[int] = None + """Virtual H200 GPU card count limit""" + + gpu_virtual_h200_count_requested: Optional[int] = None + """Virtual H200 GPU card count requested""" + + gpu_virtual_h200_count_usage: Optional[int] = None + """Virtual H200 GPU card count usage""" + + gpu_virtual_l40s_count_limit: Optional[int] = None + """Virtual L40S GPU card count limit""" + + gpu_virtual_l40s_count_requested: Optional[int] = None + """Virtual L40S GPU card count requested""" + + gpu_virtual_l40s_count_usage: Optional[int] = None + """Virtual L40S GPU card count usage""" + + laas_topic_count_limit: Optional[int] = None + """LaaS Topics Count limit""" + + laas_topic_count_requested: Optional[int] = None + """LaaS Topics Count requested""" + + laas_topic_count_usage: Optional[int] = None + """LaaS Topics Count usage""" + + loadbalancer_count_limit: Optional[int] = None + """Load Balancers Count limit""" + + loadbalancer_count_requested: Optional[int] = None + """Load Balancers Count requested""" + + loadbalancer_count_usage: Optional[int] = None + """Load Balancers Count usage""" + + ram_limit: Optional[int] = None + """RAM Size, MiB limit""" + + ram_requested: Optional[int] = None + """RAM Size, MiB requested""" + + ram_usage: Optional[int] = None + """RAM Size, MiB usage""" + + servergroup_count_limit: Optional[int] = None + """Placement Group Count limit""" + + servergroup_count_requested: Optional[int] = None + """Placement Group Count requested""" + + servergroup_count_usage: Optional[int] = None + """Placement Group Count usage""" + + vm_count_limit: Optional[int] = None + """VMs Count limit""" + + vm_count_requested: Optional[int] = None + """VMs Count requested""" + + vm_count_usage: Optional[int] = None + """VMs Count usage""" + + volume_count_limit: Optional[int] = None + """Volumes Count limit""" + + volume_count_requested: Optional[int] = None + """Volumes Count requested""" + + volume_count_usage: Optional[int] = None + """Volumes Count usage""" + + volume_size_limit: Optional[int] = None + """Volumes Size, GiB limit""" + + volume_size_requested: Optional[int] = None + """Volumes Size, GiB requested""" + + volume_size_usage: Optional[int] = None + """Volumes Size, GiB usage""" diff --git a/src/gcore/types/cloud/k8s/clusters/node_list_params.py b/src/gcore/types/cloud/k8s/clusters/node_list_params.py new file mode 100644 index 00000000..390c627e --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/node_list_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["NodeListParams"] + + +class NodeListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + with_ddos: bool + """Include DDoS profile information if set to true. Default is false.""" diff --git a/src/gcore/types/cloud/k8s/clusters/pool_check_quota_params.py b/src/gcore/types/cloud/k8s/clusters/pool_check_quota_params.py new file mode 100644 index 00000000..06880774 --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/pool_check_quota_params.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["PoolCheckQuotaParams"] + + +class PoolCheckQuotaParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + flavor_id: Required[str] + """Flavor ID""" + + boot_volume_size: Optional[int] + """Boot volume size""" + + max_node_count: Optional[int] + """Maximum node count""" + + min_node_count: Optional[int] + """Minimum node count""" + + name: Optional[str] + """Name of the cluster pool""" + + node_count: Optional[int] + """Maximum node count""" + + servergroup_policy: Optional[Literal["affinity", "anti-affinity", "soft-anti-affinity"]] + """Server group policy: anti-affinity, soft-anti-affinity or affinity""" diff --git a/src/gcore/types/cloud/k8s/clusters/pool_create_params.py b/src/gcore/types/cloud/k8s/clusters/pool_create_params.py new file mode 100644 index 00000000..c7fa5d12 --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/pool_create_params.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["PoolCreateParams"] + + +class PoolCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + flavor_id: Required[str] + """Flavor ID""" + + min_node_count: Required[int] + """Minimum node count""" + + name: Required[str] + """Pool's name""" + + auto_healing_enabled: Optional[bool] + """Enable auto healing""" + + boot_volume_size: Optional[int] + """Boot volume size""" + + boot_volume_type: Optional[Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"]] + """Boot volume type""" + + crio_config: Optional[Dict[str, str]] + """Cri-o configuration for pool nodes""" + + is_public_ipv4: Optional[bool] + """Enable public v4 address""" + + kubelet_config: Optional[Dict[str, str]] + """Kubelet configuration for pool nodes""" + + labels: Optional[Dict[str, str]] + """Labels applied to the cluster pool""" + + max_node_count: Optional[int] + """Maximum node count""" + + servergroup_policy: Optional[Literal["affinity", "anti-affinity", "soft-anti-affinity"]] + """Server group policy: anti-affinity, soft-anti-affinity or affinity""" + + taints: Optional[Dict[str, str]] + """Taints applied to the cluster pool""" diff --git a/src/gcore/types/cloud/k8s/clusters/pool_resize_params.py b/src/gcore/types/cloud/k8s/clusters/pool_resize_params.py new file mode 100644 index 00000000..356f779d --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/pool_resize_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["PoolResizeParams"] + + +class PoolResizeParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + cluster_name: Required[str] + """Cluster name""" + + node_count: Required[int] + """Target node count""" diff --git a/src/gcore/types/cloud/k8s/clusters/pool_update_params.py b/src/gcore/types/cloud/k8s/clusters/pool_update_params.py new file mode 100644 index 00000000..eb7c4b71 --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/pool_update_params.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Required, TypedDict + +__all__ = ["PoolUpdateParams"] + + +class PoolUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + cluster_name: Required[str] + """Cluster name""" + + auto_healing_enabled: Optional[bool] + """Enable/disable auto healing""" + + labels: Optional[Dict[str, str]] + """Labels applied to the cluster pool""" + + max_node_count: Optional[int] + """Maximum node count""" + + min_node_count: Optional[int] + """Minimum node count""" + + node_count: Optional[int] + """This field is deprecated. Please use the cluster pool resize handler instead.""" + + taints: Optional[Dict[str, str]] + """Taints applied to the cluster pool""" diff --git a/src/gcore/types/cloud/k8s/clusters/pools/__init__.py b/src/gcore/types/cloud/k8s/clusters/pools/__init__.py new file mode 100644 index 00000000..b0b7da06 --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/pools/__init__.py @@ -0,0 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .node_list_params import NodeListParams as NodeListParams diff --git a/src/gcore/types/cloud/k8s/clusters/pools/node_list_params.py b/src/gcore/types/cloud/k8s/clusters/pools/node_list_params.py new file mode 100644 index 00000000..fd6f0bb2 --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/pools/node_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["NodeListParams"] + + +class NodeListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + cluster_name: Required[str] + """Cluster name""" + + with_ddos: bool + """Include DDoS profile information if set to true. Default is false.""" diff --git a/src/gcore/types/cloud/k8s/flavor_list_params.py b/src/gcore/types/cloud/k8s/flavor_list_params.py new file mode 100644 index 00000000..10232583 --- /dev/null +++ b/src/gcore/types/cloud/k8s/flavor_list_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["FlavorListParams"] + + +class FlavorListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + exclude_gpu: bool + """Set to true to exclude GPU flavors. Default is false.""" + + include_capacity: bool + """Set to true to include flavor capacity. Default is False.""" + + include_prices: bool + """Set to true to include flavor prices. Default is False.""" diff --git a/src/gcore/types/cloud/k8s/k8s_cluster.py b/src/gcore/types/cloud/k8s/k8s_cluster.py new file mode 100644 index 00000000..283626ba --- /dev/null +++ b/src/gcore/types/cloud/k8s/k8s_cluster.py @@ -0,0 +1,266 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ..logging import Logging +from ...._models import BaseModel +from .clusters.k8s_cluster_pool import K8SClusterPool + +__all__ = [ + "K8SCluster", + "AddOns", + "AddOnsSlurm", + "Csi", + "CsiNfs", + "Authentication", + "AuthenticationOidc", + "Cni", + "CniCilium", + "DDOSProfile", + "DDOSProfileField", +] + + +class AddOnsSlurm(BaseModel): + """Slurm add-on configuration""" + + enabled: bool + """Indicates whether Slurm add-on is deployed in the cluster. + + This add-on is only supported in clusters running Kubernetes v1.31 and v1.32 + with at least 1 GPU cluster pool. + """ + + file_share_id: Optional[str] = None + """ID of a VAST file share used as Slurm storage. + + The Slurm add-on creates separate Persistent Volume Claims for different + purposes (controller spool, worker spool, jail) on that file share. + """ + + ssh_key_ids: Optional[List[str]] = None + """IDs of SSH keys authorized for SSH connection to Slurm login nodes.""" + + worker_count: Optional[int] = None + """Size of the worker pool, i.e. number of worker nodes. + + Each Slurm worker node is backed by a Pod scheduled on one of cluster's GPU + nodes. + + Note: Downscaling (reducing worker count) is not supported. + """ + + +class AddOns(BaseModel): + """Cluster add-ons configuration""" + + slurm: AddOnsSlurm + """Slurm add-on configuration""" + + +class CsiNfs(BaseModel): + """NFS settings""" + + vast_enabled: bool + """Indicates the status of VAST NFS integration""" + + +class Csi(BaseModel): + """Cluster CSI settings""" + + nfs: CsiNfs + """NFS settings""" + + +class AuthenticationOidc(BaseModel): + """OIDC authentication settings""" + + client_id: Optional[str] = None + """Client ID""" + + groups_claim: Optional[str] = None + """JWT claim to use as the user's group""" + + groups_prefix: Optional[str] = None + """Prefix prepended to group claims""" + + issuer_url: Optional[str] = None + """Issuer URL""" + + required_claims: Optional[Dict[str, str]] = None + """Key-value pairs that describe required claims in the token""" + + signing_algs: Optional[ + List[Literal["ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "RS256", "RS384", "RS512"]] + ] = None + """Accepted signing algorithms""" + + username_claim: Optional[str] = None + """JWT claim to use as the user name""" + + username_prefix: Optional[str] = None + """Prefix prepended to username claims to prevent clashes""" + + +class Authentication(BaseModel): + """Cluster authentication settings""" + + kubeconfig_created_at: Optional[datetime] = None + """Kubeconfig creation date""" + + kubeconfig_expires_at: Optional[datetime] = None + """Kubeconfig expiration date""" + + oidc: Optional[AuthenticationOidc] = None + """OIDC authentication settings""" + + +class CniCilium(BaseModel): + """Cilium settings""" + + encryption: Optional[bool] = None + """Wireguard encryption""" + + hubble_relay: Optional[bool] = None + """Hubble Relay""" + + hubble_ui: Optional[bool] = None + """Hubble UI""" + + lb_acceleration: Optional[bool] = None + """LoadBalancer acceleration""" + + lb_mode: Optional[Literal["dsr", "hybrid", "snat"]] = None + """LoadBalancer mode""" + + mask_size: Optional[int] = None + """Mask size for IPv4""" + + mask_size_v6: Optional[int] = None + """Mask size for IPv6""" + + routing_mode: Optional[Literal["native", "tunnel"]] = None + """Routing mode""" + + tunnel: Optional[Literal["", "geneve", "vxlan"]] = None + """CNI provider""" + + +class Cni(BaseModel): + """Cluster CNI settings""" + + cilium: Optional[CniCilium] = None + """Cilium settings""" + + provider: Optional[Literal["calico", "cilium"]] = None + """CNI provider""" + + +class DDOSProfileField(BaseModel): + base_field: int + + field_value: Optional[object] = None + """Complex value. Only one of 'value' or 'field_value' must be specified""" + + value: Optional[str] = None + """Basic value. Only one of 'value' or 'field_value' must be specified""" + + +class DDOSProfile(BaseModel): + """Advanced DDoS Protection profile""" + + enabled: bool + """Enable advanced DDoS protection""" + + fields: Optional[List[DDOSProfileField]] = None + """DDoS profile parameters""" + + profile_template: Optional[int] = None + """DDoS profile template ID""" + + profile_template_name: Optional[str] = None + """DDoS profile template name""" + + +class K8SCluster(BaseModel): + id: str + """Cluster pool uuid""" + + add_ons: AddOns + """Cluster add-ons configuration""" + + created_at: str + """Function creation date""" + + csi: Csi + """Cluster CSI settings""" + + is_public: bool + """Cluster is public""" + + keypair: str + """Keypair""" + + logging: Optional[Logging] = None + """Logging configuration""" + + name: str + """Name""" + + pools: List[K8SClusterPool] + """pools""" + + status: Literal["Deleting", "Provisioned", "Provisioning"] + """Status""" + + version: str + """K8s version""" + + authentication: Optional[Authentication] = None + """Cluster authentication settings""" + + autoscaler_config: Optional[Dict[str, str]] = None + """Cluster autoscaler configuration. + + It contains overrides to the default cluster-autoscaler parameters provided by + the platform. + """ + + cni: Optional[Cni] = None + """Cluster CNI settings""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + ddos_profile: Optional[DDOSProfile] = None + """Advanced DDoS Protection profile""" + + fixed_network: Optional[str] = None + """Fixed network id""" + + fixed_subnet: Optional[str] = None + """Fixed subnet id""" + + is_ipv6: Optional[bool] = None + """Enable public v6 address""" + + pods_ip_pool: Optional[str] = None + """The IP pool for the pods""" + + pods_ipv6_pool: Optional[str] = None + """The IPv6 pool for the pods""" + + services_ip_pool: Optional[str] = None + """The IP pool for the services""" + + services_ipv6_pool: Optional[str] = None + """The IPv6 pool for the services""" + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ diff --git a/src/gcore/types/cloud/k8s/k8s_cluster_certificate.py b/src/gcore/types/cloud/k8s/k8s_cluster_certificate.py new file mode 100644 index 00000000..03e30bf1 --- /dev/null +++ b/src/gcore/types/cloud/k8s/k8s_cluster_certificate.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["K8SClusterCertificate"] + + +class K8SClusterCertificate(BaseModel): + certificate: str + """Cluster CA certificate""" + + key: str + """Cluster CA private key""" diff --git a/src/gcore/types/cloud/k8s/k8s_cluster_kubeconfig.py b/src/gcore/types/cloud/k8s/k8s_cluster_kubeconfig.py new file mode 100644 index 00000000..6ee2cccd --- /dev/null +++ b/src/gcore/types/cloud/k8s/k8s_cluster_kubeconfig.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ...._models import BaseModel + +__all__ = ["K8SClusterKubeconfig"] + + +class K8SClusterKubeconfig(BaseModel): + client_certificate: str + """String in base64 format. Cluster client certificate""" + + client_key: str + """String in base64 format. Cluster client key""" + + cluster_ca_certificate: str + """String in base64 format. Cluster ca certificate""" + + config: str + """Cluster kubeconfig""" + + created_at: datetime + """Kubeconfig creation date""" + + expires_at: datetime + """Kubeconfig expiration date""" + + host: str + """Cluster host""" diff --git a/src/gcore/types/cloud/k8s/k8s_cluster_list.py b/src/gcore/types/cloud/k8s/k8s_cluster_list.py new file mode 100644 index 00000000..bc252f6b --- /dev/null +++ b/src/gcore/types/cloud/k8s/k8s_cluster_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ...._models import BaseModel +from .k8s_cluster import K8SCluster + +__all__ = ["K8SClusterList"] + + +class K8SClusterList(BaseModel): + count: int + """Number of objects""" + + results: List[K8SCluster] + """Objects""" diff --git a/src/gcore/types/cloud/k8s_cluster_version.py b/src/gcore/types/cloud/k8s_cluster_version.py new file mode 100644 index 00000000..257cf728 --- /dev/null +++ b/src/gcore/types/cloud/k8s_cluster_version.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["K8SClusterVersion"] + + +class K8SClusterVersion(BaseModel): + version: str + """List of supported Kubernetes cluster versions""" diff --git a/src/gcore/types/cloud/k8s_cluster_version_list.py b/src/gcore/types/cloud/k8s_cluster_version_list.py new file mode 100644 index 00000000..2f66ffb7 --- /dev/null +++ b/src/gcore/types/cloud/k8s_cluster_version_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .k8s_cluster_version import K8SClusterVersion + +__all__ = ["K8SClusterVersionList"] + + +class K8SClusterVersionList(BaseModel): + count: int + """Number of objects""" + + results: List[K8SClusterVersion] + """Objects""" diff --git a/src/gcore/types/cloud/laas_index_retention_policy.py b/src/gcore/types/cloud/laas_index_retention_policy.py new file mode 100644 index 00000000..c14c24f3 --- /dev/null +++ b/src/gcore/types/cloud/laas_index_retention_policy.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["LaasIndexRetentionPolicy"] + + +class LaasIndexRetentionPolicy(BaseModel): + period: Optional[int] = None + """Duration of days for which logs must be kept.""" diff --git a/src/gcore/types/cloud/laas_index_retention_policy_param.py b/src/gcore/types/cloud/laas_index_retention_policy_param.py new file mode 100644 index 00000000..cbe32a67 --- /dev/null +++ b/src/gcore/types/cloud/laas_index_retention_policy_param.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +__all__ = ["LaasIndexRetentionPolicyParam"] + + +class LaasIndexRetentionPolicyParam(TypedDict, total=False): + period: Required[Optional[int]] + """Duration of days for which logs must be kept.""" diff --git a/src/gcore/types/cloud/lb_algorithm.py b/src/gcore/types/cloud/lb_algorithm.py new file mode 100644 index 00000000..8d49ada2 --- /dev/null +++ b/src/gcore/types/cloud/lb_algorithm.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["LbAlgorithm"] + +LbAlgorithm: TypeAlias = Literal["LEAST_CONNECTIONS", "ROUND_ROBIN", "SOURCE_IP"] diff --git a/src/gcore/types/cloud/lb_health_monitor_type.py b/src/gcore/types/cloud/lb_health_monitor_type.py new file mode 100644 index 00000000..b433b99a --- /dev/null +++ b/src/gcore/types/cloud/lb_health_monitor_type.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["LbHealthMonitorType"] + +LbHealthMonitorType: TypeAlias = Literal["HTTP", "HTTPS", "K8S", "PING", "TCP", "TLS-HELLO", "UDP-CONNECT"] diff --git a/src/gcore/types/cloud/lb_listener_protocol.py b/src/gcore/types/cloud/lb_listener_protocol.py new file mode 100644 index 00000000..06fdedec --- /dev/null +++ b/src/gcore/types/cloud/lb_listener_protocol.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["LbListenerProtocol"] + +LbListenerProtocol: TypeAlias = Literal["HTTP", "HTTPS", "PROMETHEUS", "TCP", "TERMINATED_HTTPS", "UDP"] diff --git a/src/gcore/types/cloud/lb_pool_protocol.py b/src/gcore/types/cloud/lb_pool_protocol.py new file mode 100644 index 00000000..2a7a30a9 --- /dev/null +++ b/src/gcore/types/cloud/lb_pool_protocol.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["LbPoolProtocol"] + +LbPoolProtocol: TypeAlias = Literal["HTTP", "HTTPS", "PROXY", "PROXYV2", "TCP", "UDP"] diff --git a/src/gcore/types/cloud/lb_session_persistence_type.py b/src/gcore/types/cloud/lb_session_persistence_type.py new file mode 100644 index 00000000..526ec28b --- /dev/null +++ b/src/gcore/types/cloud/lb_session_persistence_type.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["LbSessionPersistenceType"] + +LbSessionPersistenceType: TypeAlias = Literal["APP_COOKIE", "HTTP_COOKIE", "SOURCE_IP"] diff --git a/src/gcore/types/cloud/listener_status.py b/src/gcore/types/cloud/listener_status.py new file mode 100644 index 00000000..6d9441a1 --- /dev/null +++ b/src/gcore/types/cloud/listener_status.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .pool_status import PoolStatus +from .provisioning_status import ProvisioningStatus +from .load_balancer_operating_status import LoadBalancerOperatingStatus + +__all__ = ["ListenerStatus"] + + +class ListenerStatus(BaseModel): + id: str + """UUID of the entity""" + + name: str + """Name of the load balancer listener""" + + operating_status: LoadBalancerOperatingStatus + """Operating status of the entity""" + + pools: List[PoolStatus] + """Pools of the Listeners""" + + provisioning_status: ProvisioningStatus + """Provisioning status of the entity""" diff --git a/src/gcore/types/cloud/load_balancer.py b/src/gcore/types/cloud/load_balancer.py new file mode 100644 index 00000000..ebd56ccd --- /dev/null +++ b/src/gcore/types/cloud/load_balancer.py @@ -0,0 +1,153 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from .tag import Tag +from .logging import Logging +from ..._models import BaseModel +from .floating_ip import FloatingIP +from .ddos_profile import DDOSProfile +from .interface_ip_family import InterfaceIPFamily +from .provisioning_status import ProvisioningStatus +from .load_balancer_statistics import LoadBalancerStatistics +from .load_balancer_instance_role import LoadBalancerInstanceRole +from .load_balancer_operating_status import LoadBalancerOperatingStatus +from .load_balancer_member_connectivity import LoadBalancerMemberConnectivity + +__all__ = ["LoadBalancer", "AdditionalVip", "Flavor", "Listener", "VrrpIP"] + + +class AdditionalVip(BaseModel): + ip_address: str + """IP address""" + + subnet_id: str + """Subnet UUID""" + + +class Flavor(BaseModel): + """Load balancer flavor (if not default)""" + + flavor_id: str + """Flavor ID is the same as name""" + + flavor_name: str + """Flavor name""" + + ram: int + """RAM size in MiB""" + + vcpus: int + """Virtual CPU count. For bare metal flavors, it's a physical CPU count""" + + +class Listener(BaseModel): + id: str + """Listener ID""" + + +class VrrpIP(BaseModel): + ip_address: str + """IP address""" + + role: LoadBalancerInstanceRole + """LoadBalancer instance role to which VRRP IP belong""" + + subnet_id: str + """Subnet UUID""" + + +class LoadBalancer(BaseModel): + id: str + """Load balancer ID""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + created_at: datetime + """Datetime when the load balancer was created""" + + name: str + """Load balancer name""" + + operating_status: LoadBalancerOperatingStatus + """Load balancer operating status""" + + project_id: int + """Project ID""" + + provisioning_status: ProvisioningStatus + """Load balancer lifecycle status""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + tags_v2: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + additional_vips: Optional[List[AdditionalVip]] = None + """List of additional IP addresses""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + ddos_profile: Optional[DDOSProfile] = None + """Loadbalancer advanced DDoS protection profile.""" + + flavor: Optional[Flavor] = None + """Load balancer flavor (if not default)""" + + floating_ips: Optional[List[FloatingIP]] = None + """List of assigned floating IPs""" + + listeners: Optional[List[Listener]] = None + """Load balancer listeners""" + + logging: Optional[Logging] = None + """Logging configuration""" + + preferred_connectivity: Optional[LoadBalancerMemberConnectivity] = None + """ + Preferred option to establish connectivity between load balancer and its pools + members + """ + + stats: Optional[LoadBalancerStatistics] = None + """Statistics of load balancer.""" + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + updated_at: Optional[datetime] = None + """Datetime when the load balancer was last updated""" + + vip_address: Optional[str] = None + """Load balancer IP address""" + + vip_ip_family: Optional[InterfaceIPFamily] = None + """Load balancer IP family""" + + vip_port_id: Optional[str] = None + """The ID of the Virtual IP (VIP) port.""" + + vrrp_ips: Optional[List[VrrpIP]] = None + """List of VRRP IP addresses""" diff --git a/src/gcore/types/cloud/load_balancer_create_params.py b/src/gcore/types/cloud/load_balancer_create_params.py new file mode 100644 index 00000000..db1d053d --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_create_params.py @@ -0,0 +1,391 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ..._types import SequenceNotStr +from .http_method import HTTPMethod +from .lb_algorithm import LbAlgorithm +from .lb_pool_protocol import LbPoolProtocol +from .interface_ip_family import InterfaceIPFamily +from .lb_listener_protocol import LbListenerProtocol +from .lb_health_monitor_type import LbHealthMonitorType +from .lb_session_persistence_type import LbSessionPersistenceType +from .laas_index_retention_policy_param import LaasIndexRetentionPolicyParam +from .load_balancer_member_connectivity import LoadBalancerMemberConnectivity + +__all__ = [ + "LoadBalancerCreateParams", + "FloatingIP", + "FloatingIPNewInstanceFloatingIPInterfaceSerializer", + "FloatingIPExistingInstanceFloatingIPInterfaceSerializer", + "Listener", + "ListenerPool", + "ListenerPoolHealthmonitor", + "ListenerPoolMember", + "ListenerPoolSessionPersistence", + "ListenerUserList", + "Logging", +] + + +class LoadBalancerCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + flavor: str + """Load balancer flavor name""" + + floating_ip: FloatingIP + """Floating IP configuration for assignment""" + + listeners: Iterable[Listener] + """Load balancer listeners. + + Maximum 50 per LB (excluding Prometheus endpoint listener). + """ + + logging: Logging + """Logging configuration""" + + name: str + """Load balancer name. Either `name` or `name_template` should be specified.""" + + name_template: str + """Load balancer name which will be changed by template. + + Either `name` or `name_template` should be specified. + """ + + preferred_connectivity: LoadBalancerMemberConnectivity + """ + Preferred option to establish connectivity between load balancer and its pools + members. L2 provides best performance, L3 provides less IPs usage. It is taking + effect only if `instance_id` + `ip_address` is provided, not `subnet_id` + + `ip_address`, because we're considering this as intentional `subnet_id` + specification. + """ + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + vip_ip_family: InterfaceIPFamily + """ + IP family for load balancer subnet auto-selection if `vip_network_id` is + specified + """ + + vip_network_id: str + """Network ID for load balancer. + + If not specified, default external network will be used. Mutually exclusive with + `vip_port_id` + """ + + vip_port_id: str + """Existing Reserved Fixed IP port ID for load balancer. + + Mutually exclusive with `vip_network_id` + """ + + vip_subnet_id: str + """Subnet ID for load balancer. + + If not specified, any subnet from `vip_network_id` will be selected. Ignored + when `vip_network_id` is not specified. + """ + + +class FloatingIPNewInstanceFloatingIPInterfaceSerializer(TypedDict, total=False): + source: Required[Literal["new"]] + """A new floating IP will be created and attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +class FloatingIPExistingInstanceFloatingIPInterfaceSerializer(TypedDict, total=False): + existing_floating_id: Required[str] + """ + An existing available floating IP id must be specified if the source is set to + `existing` + """ + + source: Required[Literal["existing"]] + """An existing available floating IP will be attached to the instance. + + A floating IP is a public IP that makes the instance accessible from the + internet, even if it only has a private IP. It works like SNAT, allowing + outgoing and incoming traffic. + """ + + +FloatingIP: TypeAlias = Union[ + FloatingIPNewInstanceFloatingIPInterfaceSerializer, FloatingIPExistingInstanceFloatingIPInterfaceSerializer +] + + +class ListenerPoolHealthmonitor(TypedDict, total=False): + """Health monitor details""" + + delay: Required[int] + """The time, in seconds, between sending probes to members""" + + max_retries: Required[int] + """Number of successes before the member is switched to ONLINE state""" + + timeout: Required[int] + """The maximum time to connect. Must be less than the delay value""" + + type: Required[LbHealthMonitorType] + """Health monitor type. Once health monitor is created, cannot be changed.""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + expected_codes: Optional[str] + """Expected HTTP response codes. + + Can be a single code or a range of codes. Can only be used together with `HTTP` + or `HTTPS` health monitor type. For example, + 200,202,300-302,401,403,404,500-504. If not specified, the default is 200. + """ + + http_method: Optional[HTTPMethod] + """HTTP method. + + Can only be used together with `HTTP` or `HTTPS` health monitor type. + """ + + max_retries_down: int + """Number of failures before the member is switched to ERROR state.""" + + url_path: Optional[str] + """URL Path. + + Defaults to '/'. Can only be used together with `HTTP` or `HTTPS` health monitor + type. + """ + + +class ListenerPoolMember(TypedDict, total=False): + address: Required[str] + """Member IP address""" + + protocol_port: Required[int] + """Member IP port""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + backup: bool + """ + Set to true if the member is a backup member, to which traffic will be sent + exclusively when all non-backup members will be unreachable. It allows to + realize ACTIVE-BACKUP load balancing without thinking about VRRP and VIP + configuration. Default is false. + """ + + instance_id: Optional[str] + """Either `subnet_id` or `instance_id` should be provided""" + + monitor_address: Optional[str] + """An alternate IP address used for health monitoring of a backend member. + + Default is null which monitors the member address. + """ + + monitor_port: Optional[int] + """An alternate protocol port used for health monitoring of a backend member. + + Default is null which monitors the member `protocol_port`. + """ + + subnet_id: Optional[str] + """`subnet_id` in which `address` is present. + + Either `subnet_id` or `instance_id` should be provided + """ + + weight: int + """Member weight. + + Valid values are 0 < `weight` <= 256, defaults to 1. Controls traffic + distribution based on the pool's load balancing algorithm: + + - `ROUND_ROBIN`: Distributes connections to each member in turn according to + weights. Higher weight = more turns in the cycle. Example: weights 3 vs 1 = + ~75% vs ~25% of requests. + - `LEAST_CONNECTIONS`: Sends new connections to the member with fewest active + connections, performing round-robin within groups of the same normalized load. + Higher weight = allowed to hold more simultaneous connections before being + considered 'more loaded'. Example: weights 2 vs 1 means 20 vs 10 active + connections is treated as balanced. + - `SOURCE_IP`: Routes clients consistently to the same member by hashing client + source IP; hash result is modulo total weight of running members. Higher + weight = more hash buckets, so more client IPs map to that member. Example: + weights 2 vs 1 = roughly two-thirds of distinct client IPs map to the + higher-weight member. + """ + + +class ListenerPoolSessionPersistence(TypedDict, total=False): + """Session persistence details""" + + type: Required[LbSessionPersistenceType] + """Session persistence type""" + + cookie_name: Optional[str] + """Should be set if app cookie or http cookie is used""" + + persistence_granularity: Optional[str] + """Subnet mask if `source_ip` is used. For UDP ports only""" + + persistence_timeout: Optional[int] + """Session persistence timeout. For UDP ports only""" + + +class ListenerPool(TypedDict, total=False): + lb_algorithm: Required[LbAlgorithm] + """Load balancer algorithm""" + + name: Required[str] + """Pool name""" + + protocol: Required[LbPoolProtocol] + """Protocol""" + + ca_secret_id: Optional[str] + """Secret ID of CA certificate bundle""" + + crl_secret_id: Optional[str] + """Secret ID of CA revocation list file""" + + healthmonitor: Optional[ListenerPoolHealthmonitor] + """Health monitor details""" + + members: Iterable[ListenerPoolMember] + """Pool members""" + + secret_id: Optional[str] + """Secret ID for TLS client authentication to the member servers""" + + session_persistence: Optional[ListenerPoolSessionPersistence] + """Session persistence details""" + + timeout_client_data: Optional[int] + """Frontend client inactivity timeout in milliseconds. + + We are recommending to use `listener.timeout_client_data` instead. + """ + + timeout_member_connect: Optional[int] + """Backend member connection timeout in milliseconds""" + + timeout_member_data: Optional[int] + """Backend member inactivity timeout in milliseconds""" + + +class ListenerUserList(TypedDict, total=False): + encrypted_password: Required[str] + """Encrypted password to auth via Basic Authentication""" + + username: Required[str] + """Username to auth via Basic Authentication""" + + +class Listener(TypedDict, total=False): + name: Required[str] + """Load balancer listener name""" + + protocol: Required[LbListenerProtocol] + """Load balancer listener protocol""" + + protocol_port: Required[int] + """Protocol port""" + + allowed_cidrs: Optional[SequenceNotStr[str]] + """Network CIDRs from which service will be accessible""" + + connection_limit: int + """Limit of the simultaneous connections. + + If -1 is provided, it is translated to the default value 100000. + """ + + insert_x_forwarded: bool + """Add headers X-Forwarded-For, X-Forwarded-Port, X-Forwarded-Proto to requests. + + Only used with HTTP or `TERMINATED_HTTPS` protocols. + """ + + pools: Iterable[ListenerPool] + """Member pools""" + + secret_id: Literal[""] + """ + ID of the secret where PKCS12 file is stored for `TERMINATED_HTTPS` or + PROMETHEUS listener + """ + + sni_secret_id: SequenceNotStr[str] + """ + List of secrets IDs containing PKCS12 format certificate/key bundles for + `TERMINATED_HTTPS` or PROMETHEUS listeners + """ + + timeout_client_data: Optional[int] + """Frontend client inactivity timeout in milliseconds""" + + timeout_member_connect: Optional[int] + """Backend member connection timeout in milliseconds. + + We are recommending to use `pool.timeout_member_connect` instead. + """ + + timeout_member_data: Optional[int] + """Backend member inactivity timeout in milliseconds. + + We are recommending to use `pool.timeout_member_data` instead. + """ + + user_list: Iterable[ListenerUserList] + """Load balancer listener list of username and encrypted password items""" + + +class Logging(TypedDict, total=False): + """Logging configuration""" + + destination_region_id: Optional[int] + """Destination region id to which the logs will be written""" + + enabled: bool + """Enable/disable forwarding logs to LaaS""" + + retention_policy: Optional[LaasIndexRetentionPolicyParam] + """The logs retention policy""" + + topic_name: Optional[str] + """The topic name to which the logs will be written""" diff --git a/src/gcore/types/cloud/load_balancer_failover_params.py b/src/gcore/types/cloud/load_balancer_failover_params.py new file mode 100644 index 00000000..90da9688 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_failover_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["LoadBalancerFailoverParams"] + + +class LoadBalancerFailoverParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + force: bool + """Validate current load balancer status before failover or not.""" diff --git a/src/gcore/types/cloud/load_balancer_flavor_detail.py b/src/gcore/types/cloud/load_balancer_flavor_detail.py new file mode 100644 index 00000000..f4040178 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_flavor_detail.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["LoadBalancerFlavorDetail"] + + +class LoadBalancerFlavorDetail(BaseModel): + flavor_id: str + """Flavor ID is the same as name""" + + flavor_name: str + """Flavor name""" + + ram: int + """RAM size in MiB""" + + vcpus: int + """Virtual CPU count. For bare metal flavors, it's a physical CPU count""" + + currency_code: Optional[str] = None + """Currency code. Shown if the `include_prices` query parameter if set to true""" + + price_per_hour: Optional[float] = None + """Price per hour. Shown if the `include_prices` query parameter if set to true""" + + price_per_month: Optional[float] = None + """Price per month. Shown if the `include_prices` query parameter if set to true""" + + price_status: Optional[Literal["error", "hide", "show"]] = None + """Price status for the UI""" diff --git a/src/gcore/types/cloud/load_balancer_flavor_list.py b/src/gcore/types/cloud/load_balancer_flavor_list.py new file mode 100644 index 00000000..9a1d170c --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_flavor_list.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union +from typing_extensions import TypeAlias + +from ..._models import BaseModel +from .load_balancer_flavor_detail import LoadBalancerFlavorDetail + +__all__ = ["LoadBalancerFlavorList", "Result", "ResultLbFlavorSerializer"] + + +class ResultLbFlavorSerializer(BaseModel): + flavor_id: str + """Flavor ID is the same as name""" + + flavor_name: str + """Flavor name""" + + ram: int + """RAM size in MiB""" + + vcpus: int + """Virtual CPU count. For bare metal flavors, it's a physical CPU count""" + + +Result: TypeAlias = Union[ResultLbFlavorSerializer, LoadBalancerFlavorDetail] + + +class LoadBalancerFlavorList(BaseModel): + count: int + """Number of objects""" + + results: List[Result] + """Objects""" diff --git a/src/gcore/types/cloud/load_balancer_get_params.py b/src/gcore/types/cloud/load_balancer_get_params.py new file mode 100644 index 00000000..d1644e83 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_get_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["LoadBalancerGetParams"] + + +class LoadBalancerGetParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + show_stats: bool + """Show statistics""" + + with_ddos: bool + """Show Advanced DDoS protection profile, if exists""" diff --git a/src/gcore/types/cloud/load_balancer_instance_role.py b/src/gcore/types/cloud/load_balancer_instance_role.py new file mode 100644 index 00000000..351ed470 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_instance_role.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["LoadBalancerInstanceRole"] + +LoadBalancerInstanceRole: TypeAlias = Literal["BACKUP", "MASTER", "STANDALONE"] diff --git a/src/gcore/types/cloud/load_balancer_l7_policy.py b/src/gcore/types/cloud/load_balancer_l7_policy.py new file mode 100644 index 00000000..1619c8f9 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_l7_policy.py @@ -0,0 +1,99 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .provisioning_status import ProvisioningStatus +from .load_balancer_operating_status import LoadBalancerOperatingStatus + +__all__ = ["LoadBalancerL7Policy", "Rule"] + + +class Rule(BaseModel): + id: str + """L7Rule ID""" + + project_id: int + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + +class LoadBalancerL7Policy(BaseModel): + id: str + """ID""" + + action: Literal["REDIRECT_PREFIX", "REDIRECT_TO_POOL", "REDIRECT_TO_URL", "REJECT"] + """Action""" + + listener_id: str + """Listener ID""" + + name: str + """Human-readable name of the policy""" + + operating_status: LoadBalancerOperatingStatus + """L7 policy operating status""" + + position: int + """The position of this policy on the listener. Positions start at 1.""" + + project_id: int + """Project ID""" + + provisioning_status: ProvisioningStatus + + redirect_http_code: Optional[int] = None + """ + Requests matching this policy will be redirected to the specified URL or Prefix + URL with the HTTP response code. Valid if action is `REDIRECT_TO_URL` or + `REDIRECT_PREFIX`. Valid options are 301, 302, 303, 307, or 308. Default is 302. + """ + + redirect_pool_id: Optional[str] = None + """Requests matching this policy will be redirected to the pool with this ID. + + Only valid if action is `REDIRECT_TO_POOL`. + """ + + redirect_prefix: Optional[str] = None + """Requests matching this policy will be redirected to this Prefix URL. + + Only valid if action is `REDIRECT_PREFIX`. + """ + + redirect_url: Optional[str] = None + """Requests matching this policy will be redirected to this URL. + + Only valid if action is `REDIRECT_TO_URL`. + """ + + region: str + """Region name""" + + region_id: int + """Region ID""" + + rules: List[Rule] + """Rules. + + All the rules associated with a given policy are logically ANDed together. A + request must match all the policy’s rules to match the policy.If you need to + express a logical OR operation between rules, then do this by creating multiple + policies with the same action. + """ + + tags: List[str] + """A list of simple strings assigned to the resource.""" + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ diff --git a/src/gcore/types/cloud/load_balancer_l7_policy_list.py b/src/gcore/types/cloud/load_balancer_l7_policy_list.py new file mode 100644 index 00000000..b1b156f1 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_l7_policy_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .load_balancer_l7_policy import LoadBalancerL7Policy + +__all__ = ["LoadBalancerL7PolicyList"] + + +class LoadBalancerL7PolicyList(BaseModel): + count: int + """Number of objects""" + + results: List[LoadBalancerL7Policy] + """Objects""" diff --git a/src/gcore/types/cloud/load_balancer_l7_rule.py b/src/gcore/types/cloud/load_balancer_l7_rule.py new file mode 100644 index 00000000..4c6b3c5d --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_l7_rule.py @@ -0,0 +1,63 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .provisioning_status import ProvisioningStatus +from .load_balancer_operating_status import LoadBalancerOperatingStatus + +__all__ = ["LoadBalancerL7Rule"] + + +class LoadBalancerL7Rule(BaseModel): + id: str + """L7Rule ID""" + + compare_type: Literal["CONTAINS", "ENDS_WITH", "EQUAL_TO", "REGEX", "STARTS_WITH"] + """The comparison type for the L7 rule""" + + invert: bool + """When true the logic of the rule is inverted. + + For example, with invert true, 'equal to' would become 'not equal to'. Default + is false. + """ + + key: Optional[str] = None + """The key to use for the comparison. + + For example, the name of the cookie to evaluate. + """ + + operating_status: LoadBalancerOperatingStatus + """L7 policy operating status""" + + project_id: int + """Project ID""" + + provisioning_status: ProvisioningStatus + + region: str + """Region name""" + + region_id: int + """Region ID""" + + tags: Optional[List[str]] = None + """A list of simple strings assigned to the l7 rule""" + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + type: Literal[ + "COOKIE", "FILE_TYPE", "HEADER", "HOST_NAME", "PATH", "SSL_CONN_HAS_CERT", "SSL_DN_FIELD", "SSL_VERIFY_RESULT" + ] + """The L7 rule type""" + + value: str + """The value to use for the comparison. For example, the file type to compare.""" diff --git a/src/gcore/types/cloud/load_balancer_l7_rule_list.py b/src/gcore/types/cloud/load_balancer_l7_rule_list.py new file mode 100644 index 00000000..58dee359 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_l7_rule_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .load_balancer_l7_rule import LoadBalancerL7Rule + +__all__ = ["LoadBalancerL7RuleList"] + + +class LoadBalancerL7RuleList(BaseModel): + count: int + """Number of objects""" + + results: List[LoadBalancerL7Rule] + """Objects""" diff --git a/src/gcore/types/cloud/load_balancer_list_params.py b/src/gcore/types/cloud/load_balancer_list_params.py new file mode 100644 index 00000000..d6a71ba9 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_list_params.py @@ -0,0 +1,64 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["LoadBalancerListParams"] + + +class LoadBalancerListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + assigned_floating: bool + """With or without assigned floating IP""" + + limit: int + """Limit of items on a single page""" + + logging_enabled: bool + """With or without logging enabled""" + + name: str + """Filter by name""" + + offset: int + """Offset in results list""" + + order_by: Literal[ + "created_at.asc", + "created_at.desc", + "flavor.asc", + "flavor.desc", + "name.asc", + "name.desc", + "operating_status.asc", + "operating_status.desc", + "provisioning_status.asc", + "provisioning_status.desc", + "updated_at.asc", + "updated_at.desc", + "vip_address.asc", + "vip_address.desc", + "vip_ip_family.asc", + "vip_ip_family.desc", + ] + """Order by field and direction.""" + + show_stats: bool + """Show statistics""" + + tag_key: SequenceNotStr[str] + """Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2""" + + tag_key_value: str + """Optional. Filter by tag key-value pairs.""" + + with_ddos: bool + """Show Advanced DDoS protection profile, if exists""" diff --git a/src/gcore/types/cloud/load_balancer_listener_detail.py b/src/gcore/types/cloud/load_balancer_listener_detail.py new file mode 100644 index 00000000..c54675d9 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_listener_detail.py @@ -0,0 +1,104 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ..._models import BaseModel +from .provisioning_status import ProvisioningStatus +from .lb_listener_protocol import LbListenerProtocol +from .load_balancer_statistics import LoadBalancerStatistics +from .load_balancer_operating_status import LoadBalancerOperatingStatus + +__all__ = ["LoadBalancerListenerDetail", "UserList"] + + +class UserList(BaseModel): + encrypted_password: str + """Encrypted password to auth via Basic Authentication""" + + username: str + """Username to auth via Basic Authentication""" + + +class LoadBalancerListenerDetail(BaseModel): + id: str + """Load balancer listener ID""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + allowed_cidrs: Optional[List[str]] = None + """Network CIDRs from which service will be accessible""" + + connection_limit: int + """Limit of simultaneous connections""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + insert_headers: Dict[str, object] + """Dictionary of additional header insertion into HTTP headers. + + Only used with HTTP and `TERMINATED_HTTPS` protocols. + """ + + load_balancer_id: Optional[str] = None + """Load balancer ID""" + + name: str + """Load balancer listener name""" + + operating_status: LoadBalancerOperatingStatus + """Listener operating status""" + + pool_count: Optional[int] = None + """Number of pools (for UI)""" + + protocol: LbListenerProtocol + """Load balancer protocol""" + + protocol_port: int + """Protocol port""" + + provisioning_status: ProvisioningStatus + """Listener lifecycle status""" + + secret_id: Optional[str] = None + """ + ID of the secret where PKCS12 file is stored for `TERMINATED_HTTPS` or + PROMETHEUS load balancer + """ + + sni_secret_id: Optional[List[str]] = None + """ + List of secret's ID containing PKCS12 format certificate/key bundles for + `TERMINATED_HTTPS` or PROMETHEUS listeners + """ + + stats: Optional[LoadBalancerStatistics] = None + """Statistics of the load balancer. + + It is available only in get functions by a flag. + """ + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + timeout_client_data: Optional[int] = None + """Frontend client inactivity timeout in milliseconds""" + + timeout_member_connect: Optional[int] = None + """Backend member connection timeout in milliseconds""" + + timeout_member_data: Optional[int] = None + """Backend member inactivity timeout in milliseconds""" + + user_list: List[UserList] + """Load balancer listener users list""" diff --git a/src/gcore/types/cloud/load_balancer_listener_list.py b/src/gcore/types/cloud/load_balancer_listener_list.py new file mode 100644 index 00000000..eb426067 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_listener_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .load_balancer_listener_detail import LoadBalancerListenerDetail + +__all__ = ["LoadBalancerListenerList"] + + +class LoadBalancerListenerList(BaseModel): + count: int + """Number of objects""" + + results: List[LoadBalancerListenerDetail] + """Objects""" diff --git a/src/gcore/types/cloud/load_balancer_member_connectivity.py b/src/gcore/types/cloud/load_balancer_member_connectivity.py new file mode 100644 index 00000000..d33a72da --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_member_connectivity.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["LoadBalancerMemberConnectivity"] + +LoadBalancerMemberConnectivity: TypeAlias = Literal["L2", "L3"] diff --git a/src/gcore/types/cloud/load_balancer_metrics.py b/src/gcore/types/cloud/load_balancer_metrics.py new file mode 100644 index 00000000..ffdf6859 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_metrics.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["LoadBalancerMetrics"] + + +class LoadBalancerMetrics(BaseModel): + cpu_util: Optional[float] = None + """CPU utilization, % (max 100% for multi-core)""" + + memory_util: Optional[float] = None + """RAM utilization, %""" + + network_bps_egress: Optional[float] = FieldInfo(alias="network_Bps_egress", default=None) + """Network out, bytes per second""" + + network_bps_ingress: Optional[float] = FieldInfo(alias="network_Bps_ingress", default=None) + """Network in, bytes per second""" + + network_pps_egress: Optional[float] = None + """Network out, packets per second""" + + network_pps_ingress: Optional[float] = None + """Network in, packets per second""" + + time: Optional[str] = None + """Timestamp""" diff --git a/src/gcore/types/cloud/load_balancer_metrics_list.py b/src/gcore/types/cloud/load_balancer_metrics_list.py new file mode 100644 index 00000000..c270faf1 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_metrics_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .load_balancer_metrics import LoadBalancerMetrics + +__all__ = ["LoadBalancerMetricsList"] + + +class LoadBalancerMetricsList(BaseModel): + count: int + """Number of objects""" + + results: List[LoadBalancerMetrics] + """Objects""" diff --git a/src/gcore/types/cloud/load_balancer_operating_status.py b/src/gcore/types/cloud/load_balancer_operating_status.py new file mode 100644 index 00000000..28dd7a7f --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_operating_status.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["LoadBalancerOperatingStatus"] + +LoadBalancerOperatingStatus: TypeAlias = Literal["DEGRADED", "DRAINING", "ERROR", "NO_MONITOR", "OFFLINE", "ONLINE"] diff --git a/src/gcore/types/cloud/load_balancer_pool.py b/src/gcore/types/cloud/load_balancer_pool.py new file mode 100644 index 00000000..3e67e0a0 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_pool.py @@ -0,0 +1,94 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .member import Member +from ..._models import BaseModel +from .lb_algorithm import LbAlgorithm +from .health_monitor import HealthMonitor +from .lb_pool_protocol import LbPoolProtocol +from .provisioning_status import ProvisioningStatus +from .session_persistence import SessionPersistence +from .load_balancer_operating_status import LoadBalancerOperatingStatus + +__all__ = ["LoadBalancerPool", "Listener", "Loadbalancer"] + + +class Listener(BaseModel): + id: str + """Resource ID""" + + +class Loadbalancer(BaseModel): + id: str + """Resource ID""" + + +class LoadBalancerPool(BaseModel): + id: str + """Pool ID""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + ca_secret_id: Optional[str] = None + """Secret ID of CA certificate bundle""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + crl_secret_id: Optional[str] = None + """Secret ID of CA revocation list file""" + + healthmonitor: Optional[HealthMonitor] = None + """Health monitor parameters""" + + lb_algorithm: LbAlgorithm + """Load balancer algorithm""" + + listeners: List[Listener] + """Listeners IDs""" + + loadbalancers: List[Loadbalancer] + """Load balancers IDs""" + + members: List[Member] + """Pool members""" + + name: str + """Pool name""" + + operating_status: LoadBalancerOperatingStatus + """Pool operating status""" + + protocol: LbPoolProtocol + """Protocol""" + + provisioning_status: ProvisioningStatus + """Pool lifecycle status""" + + secret_id: Optional[str] = None + """Secret ID for TLS client authentication to the member servers""" + + session_persistence: Optional[SessionPersistence] = None + """Session persistence parameters""" + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + timeout_client_data: Optional[int] = None + """Frontend client inactivity timeout in milliseconds""" + + timeout_member_connect: Optional[int] = None + """Backend member connection timeout in milliseconds""" + + timeout_member_data: Optional[int] = None + """Backend member inactivity timeout in milliseconds""" diff --git a/src/gcore/types/cloud/load_balancer_pool_list.py b/src/gcore/types/cloud/load_balancer_pool_list.py new file mode 100644 index 00000000..08f1422a --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_pool_list.py @@ -0,0 +1,118 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import TypeAlias + +from .member import Member +from ..._models import BaseModel +from .lb_algorithm import LbAlgorithm +from .health_monitor import HealthMonitor +from .lb_pool_protocol import LbPoolProtocol +from .provisioning_status import ProvisioningStatus +from .session_persistence import SessionPersistence +from .load_balancer_operating_status import LoadBalancerOperatingStatus + +__all__ = [ + "LoadBalancerPoolList", + "Result", + "ResultListener", + "ResultLoadbalancer", + "ResultMember", + "ResultMemberLbPoolMemberSerializer", +] + + +class ResultListener(BaseModel): + id: str + """Resource ID""" + + +class ResultLoadbalancer(BaseModel): + id: str + """Resource ID""" + + +class ResultMemberLbPoolMemberSerializer(BaseModel): + id: str + """Member ID must be provided if an existing member is being updated""" + + +ResultMember: TypeAlias = Union[ResultMemberLbPoolMemberSerializer, Member] + + +class Result(BaseModel): + id: str + """Pool ID""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + ca_secret_id: Optional[str] = None + """Secret ID of CA certificate bundle""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + crl_secret_id: Optional[str] = None + """Secret ID of CA revocation list file""" + + healthmonitor: Optional[HealthMonitor] = None + """Health monitor parameters""" + + lb_algorithm: LbAlgorithm + """Load balancer algorithm""" + + listeners: List[ResultListener] + """Listeners IDs""" + + loadbalancers: List[ResultLoadbalancer] + """Load balancers IDs""" + + members: List[ResultMember] + """Pool members""" + + name: str + """Pool name""" + + operating_status: LoadBalancerOperatingStatus + """Pool operating status""" + + protocol: LbPoolProtocol + """Protocol""" + + provisioning_status: ProvisioningStatus + """Pool lifecycle status""" + + secret_id: Optional[str] = None + """Secret ID for TLS client authentication to the member servers""" + + session_persistence: Optional[SessionPersistence] = None + """Session persistence parameters""" + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + timeout_client_data: Optional[int] = None + """Frontend client inactivity timeout in milliseconds""" + + timeout_member_connect: Optional[int] = None + """Backend member connection timeout in milliseconds""" + + timeout_member_data: Optional[int] = None + """Backend member inactivity timeout in milliseconds""" + + +class LoadBalancerPoolList(BaseModel): + count: int + """Number of objects""" + + results: List[Result] + """Objects""" diff --git a/src/gcore/types/cloud/load_balancer_resize_params.py b/src/gcore/types/cloud/load_balancer_resize_params.py new file mode 100644 index 00000000..80d1a0b5 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_resize_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["LoadBalancerResizeParams"] + + +class LoadBalancerResizeParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + flavor: Required[str] + """Name of the desired flavor to resize to.""" diff --git a/src/gcore/types/cloud/load_balancer_statistics.py b/src/gcore/types/cloud/load_balancer_statistics.py new file mode 100644 index 00000000..903a605a --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_statistics.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["LoadBalancerStatistics"] + + +class LoadBalancerStatistics(BaseModel): + active_connections: int + """Currently active connections""" + + bytes_in: int + """Total bytes received""" + + bytes_out: int + """Total bytes sent""" + + request_errors: int + """Total requests that were unable to be fulfilled""" + + total_connections: int + """Total connections handled""" diff --git a/src/gcore/types/cloud/load_balancer_status.py b/src/gcore/types/cloud/load_balancer_status.py new file mode 100644 index 00000000..9560af29 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_status.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .tag import Tag +from ..._models import BaseModel +from .listener_status import ListenerStatus +from .provisioning_status import ProvisioningStatus +from .load_balancer_operating_status import LoadBalancerOperatingStatus + +__all__ = ["LoadBalancerStatus"] + + +class LoadBalancerStatus(BaseModel): + id: str + """UUID of the entity""" + + listeners: List[ListenerStatus] + """Listeners of the Load Balancer""" + + name: str + """Name of the load balancer""" + + operating_status: LoadBalancerOperatingStatus + """Operating status of the entity""" + + provisioning_status: ProvisioningStatus + """Provisioning status of the entity""" + + tags: Optional[List[Tag]] = None + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ diff --git a/src/gcore/types/cloud/load_balancer_status_list.py b/src/gcore/types/cloud/load_balancer_status_list.py new file mode 100644 index 00000000..0432a12c --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_status_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .load_balancer_status import LoadBalancerStatus + +__all__ = ["LoadBalancerStatusList"] + + +class LoadBalancerStatusList(BaseModel): + count: int + """Number of objects""" + + results: List[LoadBalancerStatus] + """Objects""" diff --git a/src/gcore/types/cloud/load_balancer_update_params.py b/src/gcore/types/cloud/load_balancer_update_params.py new file mode 100644 index 00000000..6bd7a916 --- /dev/null +++ b/src/gcore/types/cloud/load_balancer_update_params.py @@ -0,0 +1,73 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +from .tag_update_map_param import TagUpdateMapParam +from .laas_index_retention_policy_param import LaasIndexRetentionPolicyParam +from .load_balancer_member_connectivity import LoadBalancerMemberConnectivity + +__all__ = ["LoadBalancerUpdateParams", "Logging"] + + +class LoadBalancerUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + logging: Logging + """Logging configuration""" + + name: str + """Name.""" + + preferred_connectivity: LoadBalancerMemberConnectivity + """ + Preferred option to establish connectivity between load balancer and its pools + members + """ + + tags: Optional[TagUpdateMapParam] + """Update key-value tags using JSON Merge Patch semantics (RFC 7386). + + Provide key-value pairs to add or update tags. Set tag values to `null` to + remove tags. Unspecified tags remain unchanged. Read-only tags are always + preserved and cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + """ + + +class Logging(TypedDict, total=False): + """Logging configuration""" + + destination_region_id: Optional[int] + """Destination region id to which the logs will be written""" + + enabled: bool + """Enable/disable forwarding logs to LaaS""" + + retention_policy: Optional[LaasIndexRetentionPolicyParam] + """The logs retention policy""" + + topic_name: Optional[str] + """The topic name to which the logs will be written""" diff --git a/src/gcore/types/cloud/load_balancers/__init__.py b/src/gcore/types/cloud/load_balancers/__init__.py new file mode 100644 index 00000000..cfacdce7 --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/__init__.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .pool_list_params import PoolListParams as PoolListParams +from .flavor_list_params import FlavorListParams as FlavorListParams +from .metric_list_params import MetricListParams as MetricListParams +from .pool_create_params import PoolCreateParams as PoolCreateParams +from .pool_update_params import PoolUpdateParams as PoolUpdateParams +from .listener_get_params import ListenerGetParams as ListenerGetParams +from .listener_list_params import ListenerListParams as ListenerListParams +from .listener_create_params import ListenerCreateParams as ListenerCreateParams +from .listener_delete_params import ListenerDeleteParams as ListenerDeleteParams +from .listener_update_params import ListenerUpdateParams as ListenerUpdateParams +from .l7_policy_create_params import L7PolicyCreateParams as L7PolicyCreateParams +from .l7_policy_update_params import L7PolicyUpdateParams as L7PolicyUpdateParams diff --git a/src/gcore/types/cloud/load_balancers/flavor_list_params.py b/src/gcore/types/cloud/load_balancers/flavor_list_params.py new file mode 100644 index 00000000..af622cd6 --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/flavor_list_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["FlavorListParams"] + + +class FlavorListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + include_prices: bool + """Set to true if the response should include flavor prices""" diff --git a/src/gcore/types/cloud/load_balancers/l7_policies/__init__.py b/src/gcore/types/cloud/load_balancers/l7_policies/__init__.py new file mode 100644 index 00000000..832f1d77 --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/l7_policies/__init__.py @@ -0,0 +1,6 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .rule_create_params import RuleCreateParams as RuleCreateParams +from .rule_replace_params import RuleReplaceParams as RuleReplaceParams diff --git a/src/gcore/types/cloud/load_balancers/l7_policies/rule_create_params.py b/src/gcore/types/cloud/load_balancers/l7_policies/rule_create_params.py new file mode 100644 index 00000000..36ffd53e --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/l7_policies/rule_create_params.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = ["RuleCreateParams"] + + +class RuleCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + compare_type: Required[Literal["CONTAINS", "ENDS_WITH", "EQUAL_TO", "REGEX", "STARTS_WITH"]] + """The comparison type for the L7 rule""" + + type: Required[ + Literal[ + "COOKIE", + "FILE_TYPE", + "HEADER", + "HOST_NAME", + "PATH", + "SSL_CONN_HAS_CERT", + "SSL_DN_FIELD", + "SSL_VERIFY_RESULT", + ] + ] + """The L7 rule type""" + + value: Required[str] + """The value to use for the comparison""" + + invert: bool + """When true the logic of the rule is inverted.""" + + key: str + """The key to use for the comparison. Required for COOKIE and HEADER `type` only.""" + + tags: SequenceNotStr[str] + """A list of simple strings assigned to the l7 rule""" diff --git a/src/gcore/types/cloud/load_balancers/l7_policies/rule_replace_params.py b/src/gcore/types/cloud/load_balancers/l7_policies/rule_replace_params.py new file mode 100644 index 00000000..ab64c93b --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/l7_policies/rule_replace_params.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from ....._types import SequenceNotStr + +__all__ = ["RuleReplaceParams"] + + +class RuleReplaceParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + l7policy_id: Required[str] + """L7 policy ID""" + + compare_type: Required[Literal["CONTAINS", "ENDS_WITH", "EQUAL_TO", "REGEX", "STARTS_WITH"]] + """The comparison type for the L7 rule""" + + invert: bool + """When true the logic of the rule is inverted.""" + + key: str + """The key to use for the comparison. Required for COOKIE and HEADER `type` only.""" + + tags: SequenceNotStr[str] + """A list of simple strings assigned to the l7 rule""" + + type: Literal[ + "COOKIE", "FILE_TYPE", "HEADER", "HOST_NAME", "PATH", "SSL_CONN_HAS_CERT", "SSL_DN_FIELD", "SSL_VERIFY_RESULT" + ] + """The L7 rule type""" + + value: str + """The value to use for the comparison""" diff --git a/src/gcore/types/cloud/load_balancers/l7_policy_create_params.py b/src/gcore/types/cloud/load_balancers/l7_policy_create_params.py new file mode 100644 index 00000000..1ab01e3f --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/l7_policy_create_params.py @@ -0,0 +1,139 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ...._types import SequenceNotStr + +__all__ = [ + "L7PolicyCreateParams", + "CreateL7PolicyRedirectToURLSerializer", + "CreateL7PolicyRedirectPrefixSerializer", + "CreateL7PolicyRedirectToPoolSerializer", + "CreateL7PolicyRejectSerializer", +] + + +class CreateL7PolicyRedirectToURLSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["REDIRECT_TO_URL"]] + """Action""" + + listener_id: Required[str] + """Listener ID""" + + redirect_url: Required[str] + """Requests matching this policy will be redirected to this URL.""" + + name: str + """Human-readable name of the policy""" + + position: int + """The position of this policy on the listener""" + + redirect_http_code: int + """ + Requests matching this policy will be redirected to the specified URL or Prefix + URL with the HTTP response code. Valid options are 301, 302, 303, 307, or 308. + Default is 302. + """ + + tags: SequenceNotStr[str] + """A list of simple strings assigned to the resource.""" + + +class CreateL7PolicyRedirectPrefixSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["REDIRECT_PREFIX"]] + """Action""" + + listener_id: Required[str] + """Listener ID""" + + redirect_prefix: Required[str] + """Requests matching this policy will be redirected to this Prefix URL.""" + + name: str + """Human-readable name of the policy""" + + position: int + """The position of this policy on the listener""" + + redirect_http_code: int + """ + Requests matching this policy will be redirected to the specified URL or Prefix + URL with the HTTP response code. Valid options are 301, 302, 303, 307, or 308. + Default is 302. + """ + + tags: SequenceNotStr[str] + """A list of simple strings assigned to the resource.""" + + +class CreateL7PolicyRedirectToPoolSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["REDIRECT_TO_POOL"]] + """Action""" + + listener_id: Required[str] + """Listener ID""" + + redirect_pool_id: Required[str] + """Requests matching this policy will be redirected to the pool with this ID.""" + + name: str + """Human-readable name of the policy""" + + position: int + """The position of this policy on the listener""" + + tags: SequenceNotStr[str] + """A list of simple strings assigned to the resource.""" + + +class CreateL7PolicyRejectSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["REJECT"]] + """Action""" + + listener_id: Required[str] + """Listener ID""" + + name: str + """Human-readable name of the policy""" + + position: int + """The position of this policy on the listener""" + + tags: SequenceNotStr[str] + """A list of simple strings assigned to the resource.""" + + +L7PolicyCreateParams: TypeAlias = Union[ + CreateL7PolicyRedirectToURLSerializer, + CreateL7PolicyRedirectPrefixSerializer, + CreateL7PolicyRedirectToPoolSerializer, + CreateL7PolicyRejectSerializer, +] diff --git a/src/gcore/types/cloud/load_balancers/l7_policy_update_params.py b/src/gcore/types/cloud/load_balancers/l7_policy_update_params.py new file mode 100644 index 00000000..f1888ed5 --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/l7_policy_update_params.py @@ -0,0 +1,130 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ...._types import SequenceNotStr + +__all__ = [ + "L7PolicyUpdateParams", + "UpdateL7PolicyRedirectToURLSerializer", + "UpdateL7PolicyRedirectPrefixSerializer", + "UpdateL7PolicyRedirectToPoolSerializer", + "UpdateL7PolicyRejectSerializer", +] + + +class UpdateL7PolicyRedirectToURLSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["REDIRECT_TO_URL"]] + """Action""" + + redirect_url: Required[str] + """Requests matching this policy will be redirected to this URL. + + Only valid if action is `REDIRECT_TO_URL`. + """ + + name: str + """Human-readable name of the policy""" + + position: int + """The position of this policy on the listener""" + + redirect_http_code: int + """ + Requests matching this policy will be redirected to the specified URL or Prefix + URL with the HTTP response code. Valid if action is `REDIRECT_TO_URL` or + `REDIRECT_PREFIX`. Valid options are 301, 302, 303, 307, or 308. Default is 302. + """ + + tags: SequenceNotStr[str] + """A list of simple strings assigned to the resource.""" + + +class UpdateL7PolicyRedirectPrefixSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["REDIRECT_PREFIX"]] + """Action""" + + redirect_prefix: Required[str] + """Requests matching this policy will be redirected to this Prefix URL.""" + + name: str + """Human-readable name of the policy""" + + position: int + """The position of this policy on the listener""" + + redirect_http_code: int + """ + Requests matching this policy will be redirected to the specified URL or Prefix + URL with the HTTP response code. Valid options are 301, 302, 303, 307, or 308. + Default is 302. + """ + + tags: SequenceNotStr[str] + """A list of simple strings assigned to the resource.""" + + +class UpdateL7PolicyRedirectToPoolSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["REDIRECT_TO_POOL"]] + """Action""" + + redirect_pool_id: Required[str] + """Requests matching this policy will be redirected to the pool with this ID.""" + + name: str + """Human-readable name of the policy""" + + position: int + """The position of this policy on the listener""" + + tags: SequenceNotStr[str] + """A list of simple strings assigned to the resource.""" + + +class UpdateL7PolicyRejectSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + action: Required[Literal["REJECT"]] + """Action""" + + name: str + """Human-readable name of the policy""" + + position: int + """The position of this policy on the listener""" + + tags: SequenceNotStr[str] + """A list of simple strings assigned to the resource.""" + + +L7PolicyUpdateParams: TypeAlias = Union[ + UpdateL7PolicyRedirectToURLSerializer, + UpdateL7PolicyRedirectPrefixSerializer, + UpdateL7PolicyRedirectToPoolSerializer, + UpdateL7PolicyRejectSerializer, +] diff --git a/src/gcore/types/cloud/load_balancers/listener_create_params.py b/src/gcore/types/cloud/load_balancers/listener_create_params.py new file mode 100644 index 00000000..652ba39a --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/listener_create_params.py @@ -0,0 +1,87 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr +from ..lb_listener_protocol import LbListenerProtocol + +__all__ = ["ListenerCreateParams", "UserList"] + + +class ListenerCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + load_balancer_id: Required[str] + """ID of already existent Load Balancer.""" + + name: Required[str] + """Load balancer listener name""" + + protocol: Required[LbListenerProtocol] + """Load balancer listener protocol""" + + protocol_port: Required[int] + """Protocol port""" + + allowed_cidrs: Optional[SequenceNotStr[str]] + """Network CIDRs from which service will be accessible""" + + connection_limit: int + """Limit of the simultaneous connections. + + If -1 is provided, it is translated to the default value 100000. + """ + + default_pool_id: str + """ID of already existent Load Balancer Pool to attach listener to.""" + + insert_x_forwarded: bool + """Add headers X-Forwarded-For, X-Forwarded-Port, X-Forwarded-Proto to requests. + + Only used with HTTP or `TERMINATED_HTTPS` protocols. + """ + + secret_id: Literal[""] + """ + ID of the secret where PKCS12 file is stored for `TERMINATED_HTTPS` or + PROMETHEUS listener + """ + + sni_secret_id: SequenceNotStr[str] + """ + List of secrets IDs containing PKCS12 format certificate/key bundles for + `TERMINATED_HTTPS` or PROMETHEUS listeners + """ + + timeout_client_data: Optional[int] + """Frontend client inactivity timeout in milliseconds""" + + timeout_member_connect: Optional[int] + """Backend member connection timeout in milliseconds. + + We are recommending to use `pool.timeout_member_connect` instead. + """ + + timeout_member_data: Optional[int] + """Backend member inactivity timeout in milliseconds. + + We are recommending to use `pool.timeout_member_data` instead. + """ + + user_list: Iterable[UserList] + """Load balancer listener list of username and encrypted password items""" + + +class UserList(TypedDict, total=False): + encrypted_password: Required[str] + """Encrypted password to auth via Basic Authentication""" + + username: Required[str] + """Username to auth via Basic Authentication""" diff --git a/src/gcore/types/cloud/load_balancers/listener_delete_params.py b/src/gcore/types/cloud/load_balancers/listener_delete_params.py new file mode 100644 index 00000000..7d0e31a4 --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/listener_delete_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ListenerDeleteParams"] + + +class ListenerDeleteParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + delete_default_pool: bool + """Delete default pool attached directly to the listener.""" diff --git a/src/gcore/types/cloud/load_balancers/listener_get_params.py b/src/gcore/types/cloud/load_balancers/listener_get_params.py new file mode 100644 index 00000000..f3825291 --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/listener_get_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ListenerGetParams"] + + +class ListenerGetParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + show_stats: bool + """Show stats""" diff --git a/src/gcore/types/cloud/load_balancers/listener_list_params.py b/src/gcore/types/cloud/load_balancers/listener_list_params.py new file mode 100644 index 00000000..c3e9925f --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/listener_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ListenerListParams"] + + +class ListenerListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + load_balancer_id: str + """Load Balancer ID""" + + show_stats: bool + """Show stats""" diff --git a/src/gcore/types/cloud/load_balancers/listener_update_params.py b/src/gcore/types/cloud/load_balancers/listener_update_params.py new file mode 100644 index 00000000..e537da9b --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/listener_update_params.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["ListenerUpdateParams", "UserList"] + + +class ListenerUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + allowed_cidrs: Optional[SequenceNotStr[str]] + """Network CIDRs from which service will be accessible""" + + connection_limit: int + """Limit of simultaneous connections. + + If -1 is provided, it is translated to the default value 100000. + """ + + name: str + """Load balancer listener name""" + + secret_id: Optional[str] + """ + ID of the secret where PKCS12 file is stored for `TERMINATED_HTTPS` or + PROMETHEUS load balancer + """ + + sni_secret_id: Optional[SequenceNotStr[str]] + """ + List of secret's ID containing PKCS12 format certificate/key bundfles for + `TERMINATED_HTTPS` or PROMETHEUS listeners + """ + + timeout_client_data: Optional[int] + """Frontend client inactivity timeout in milliseconds""" + + timeout_member_connect: Optional[int] + """Backend member connection timeout in milliseconds. + + We are recommending to use `pool.timeout_member_connect` instead. + """ + + timeout_member_data: Optional[int] + """Backend member inactivity timeout in milliseconds. + + We are recommending to use `pool.timeout_member_data` instead. + """ + + user_list: Optional[Iterable[UserList]] + """Load balancer listener users list""" + + +class UserList(TypedDict, total=False): + encrypted_password: Required[str] + """Encrypted password to auth via Basic Authentication""" + + username: Required[str] + """Username to auth via Basic Authentication""" diff --git a/src/gcore/types/cloud/load_balancers/metric_list_params.py b/src/gcore/types/cloud/load_balancers/metric_list_params.py new file mode 100644 index 00000000..a88d2c11 --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/metric_list_params.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from ..instance_metrics_time_unit import InstanceMetricsTimeUnit + +__all__ = ["MetricListParams"] + + +class MetricListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + time_interval: Required[int] + """Time interval""" + + time_unit: Required[InstanceMetricsTimeUnit] + """Time interval unit""" diff --git a/src/gcore/types/cloud/load_balancers/pool_create_params.py b/src/gcore/types/cloud/load_balancers/pool_create_params.py new file mode 100644 index 00000000..2feef950 --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/pool_create_params.py @@ -0,0 +1,195 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Required, TypedDict + +from ..http_method import HTTPMethod +from ..lb_algorithm import LbAlgorithm +from ..lb_pool_protocol import LbPoolProtocol +from ..lb_health_monitor_type import LbHealthMonitorType +from ..lb_session_persistence_type import LbSessionPersistenceType + +__all__ = ["PoolCreateParams", "Healthmonitor", "Member", "SessionPersistence"] + + +class PoolCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + lb_algorithm: Required[LbAlgorithm] + """Load balancer algorithm""" + + name: Required[str] + """Pool name""" + + protocol: Required[LbPoolProtocol] + """Protocol""" + + ca_secret_id: Optional[str] + """Secret ID of CA certificate bundle""" + + crl_secret_id: Optional[str] + """Secret ID of CA revocation list file""" + + healthmonitor: Optional[Healthmonitor] + """Health monitor details""" + + listener_id: Optional[str] + """Listener ID""" + + load_balancer_id: Optional[str] + """Loadbalancer ID""" + + members: Iterable[Member] + """Pool members""" + + secret_id: Optional[str] + """Secret ID for TLS client authentication to the member servers""" + + session_persistence: Optional[SessionPersistence] + """Session persistence details""" + + timeout_client_data: Optional[int] + """Frontend client inactivity timeout in milliseconds. + + We are recommending to use `listener.timeout_client_data` instead. + """ + + timeout_member_connect: Optional[int] + """Backend member connection timeout in milliseconds""" + + timeout_member_data: Optional[int] + """Backend member inactivity timeout in milliseconds""" + + +class Healthmonitor(TypedDict, total=False): + """Health monitor details""" + + delay: Required[int] + """The time, in seconds, between sending probes to members""" + + max_retries: Required[int] + """Number of successes before the member is switched to ONLINE state""" + + timeout: Required[int] + """The maximum time to connect. Must be less than the delay value""" + + type: Required[LbHealthMonitorType] + """Health monitor type. Once health monitor is created, cannot be changed.""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + expected_codes: Optional[str] + """Expected HTTP response codes. + + Can be a single code or a range of codes. Can only be used together with `HTTP` + or `HTTPS` health monitor type. For example, + 200,202,300-302,401,403,404,500-504. If not specified, the default is 200. + """ + + http_method: Optional[HTTPMethod] + """HTTP method. + + Can only be used together with `HTTP` or `HTTPS` health monitor type. + """ + + max_retries_down: int + """Number of failures before the member is switched to ERROR state.""" + + url_path: Optional[str] + """URL Path. + + Defaults to '/'. Can only be used together with `HTTP` or `HTTPS` health monitor + type. + """ + + +class Member(TypedDict, total=False): + address: Required[str] + """Member IP address""" + + protocol_port: Required[int] + """Member IP port""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + backup: bool + """ + Set to true if the member is a backup member, to which traffic will be sent + exclusively when all non-backup members will be unreachable. It allows to + realize ACTIVE-BACKUP load balancing without thinking about VRRP and VIP + configuration. Default is false. + """ + + instance_id: Optional[str] + """Either `subnet_id` or `instance_id` should be provided""" + + monitor_address: Optional[str] + """An alternate IP address used for health monitoring of a backend member. + + Default is null which monitors the member address. + """ + + monitor_port: Optional[int] + """An alternate protocol port used for health monitoring of a backend member. + + Default is null which monitors the member `protocol_port`. + """ + + subnet_id: Optional[str] + """`subnet_id` in which `address` is present. + + Either `subnet_id` or `instance_id` should be provided + """ + + weight: int + """Member weight. + + Valid values are 0 < `weight` <= 256, defaults to 1. Controls traffic + distribution based on the pool's load balancing algorithm: + + - `ROUND_ROBIN`: Distributes connections to each member in turn according to + weights. Higher weight = more turns in the cycle. Example: weights 3 vs 1 = + ~75% vs ~25% of requests. + - `LEAST_CONNECTIONS`: Sends new connections to the member with fewest active + connections, performing round-robin within groups of the same normalized load. + Higher weight = allowed to hold more simultaneous connections before being + considered 'more loaded'. Example: weights 2 vs 1 means 20 vs 10 active + connections is treated as balanced. + - `SOURCE_IP`: Routes clients consistently to the same member by hashing client + source IP; hash result is modulo total weight of running members. Higher + weight = more hash buckets, so more client IPs map to that member. Example: + weights 2 vs 1 = roughly two-thirds of distinct client IPs map to the + higher-weight member. + """ + + +class SessionPersistence(TypedDict, total=False): + """Session persistence details""" + + type: Required[LbSessionPersistenceType] + """Session persistence type""" + + cookie_name: Optional[str] + """Should be set if app cookie or http cookie is used""" + + persistence_granularity: Optional[str] + """Subnet mask if `source_ip` is used. For UDP ports only""" + + persistence_timeout: Optional[int] + """Session persistence timeout. For UDP ports only""" diff --git a/src/gcore/types/cloud/load_balancers/pool_list_params.py b/src/gcore/types/cloud/load_balancers/pool_list_params.py new file mode 100644 index 00000000..1cddb97b --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/pool_list_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["PoolListParams"] + + +class PoolListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + details: bool + """Show members and Health Monitor details""" + + listener_id: str + """Listener ID""" + + load_balancer_id: str + """Load Balancer ID""" diff --git a/src/gcore/types/cloud/load_balancers/pool_update_params.py b/src/gcore/types/cloud/load_balancers/pool_update_params.py new file mode 100644 index 00000000..e18d418e --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/pool_update_params.py @@ -0,0 +1,200 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Required, TypedDict + +from ..http_method import HTTPMethod +from ..lb_algorithm import LbAlgorithm +from ..lb_pool_protocol import LbPoolProtocol +from ..lb_health_monitor_type import LbHealthMonitorType +from ..lb_session_persistence_type import LbSessionPersistenceType + +__all__ = ["PoolUpdateParams", "Healthmonitor", "Member", "SessionPersistence"] + + +class PoolUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + ca_secret_id: Optional[str] + """Secret ID of CA certificate bundle""" + + crl_secret_id: Optional[str] + """Secret ID of CA revocation list file""" + + healthmonitor: Optional[Healthmonitor] + """New pool health monitor settings""" + + lb_algorithm: LbAlgorithm + """New load balancer pool algorithm of how to distribute requests""" + + members: Optional[Iterable[Member]] + """New sequence of load balancer pool members. + + If members are the same (by address + port), they will be kept as is without + recreation and downtime. + """ + + name: str + """New pool name""" + + protocol: LbPoolProtocol + """New communication protocol""" + + secret_id: Optional[str] + """Secret ID for TLS client authentication to the member servers""" + + session_persistence: Optional[SessionPersistence] + """New session persistence settings""" + + timeout_client_data: Optional[int] + """Frontend client inactivity timeout in milliseconds. + + We are recommending to use `listener.timeout_client_data` instead. + """ + + timeout_member_connect: Optional[int] + """Backend member connection timeout in milliseconds""" + + timeout_member_data: Optional[int] + """Backend member inactivity timeout in milliseconds""" + + +class Healthmonitor(TypedDict, total=False): + """New pool health monitor settings""" + + delay: Required[int] + """The time, in seconds, between sending probes to members""" + + max_retries: Required[int] + """Number of successes before the member is switched to ONLINE state""" + + timeout: Required[int] + """The maximum time to connect. Must be less than the delay value""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + expected_codes: Optional[str] + """Expected HTTP response codes. + + Can be a single code or a range of codes. Can only be used together with `HTTP` + or `HTTPS` health monitor type. For example, + 200,202,300-302,401,403,404,500-504. If not specified, the default is 200. + """ + + http_method: Optional[HTTPMethod] + """HTTP method. + + Can only be used together with `HTTP` or `HTTPS` health monitor type. + """ + + max_retries_down: int + """Number of failures before the member is switched to ERROR state.""" + + type: Optional[LbHealthMonitorType] + """Health monitor type. Once health monitor is created, cannot be changed.""" + + url_path: Optional[str] + """URL Path. + + Defaults to '/'. Can only be used together with `HTTP` or `HTTPS` health monitor + type. + """ + + +class Member(TypedDict, total=False): + address: Required[str] + """Member IP address""" + + protocol_port: Required[int] + """Member IP port""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + backup: bool + """ + Set to true if the member is a backup member, to which traffic will be sent + exclusively when all non-backup members will be unreachable. It allows to + realize ACTIVE-BACKUP load balancing without thinking about VRRP and VIP + configuration. Default is false. + """ + + instance_id: Optional[str] + """Either `subnet_id` or `instance_id` should be provided""" + + monitor_address: Optional[str] + """An alternate IP address used for health monitoring of a backend member. + + Default is null which monitors the member address. + """ + + monitor_port: Optional[int] + """An alternate protocol port used for health monitoring of a backend member. + + Default is null which monitors the member `protocol_port`. + """ + + subnet_id: Optional[str] + """`subnet_id` in which `address` is present. + + Either `subnet_id` or `instance_id` should be provided + """ + + weight: int + """Member weight. + + Valid values are 0 < `weight` <= 256, defaults to 1. Controls traffic + distribution based on the pool's load balancing algorithm: + + - `ROUND_ROBIN`: Distributes connections to each member in turn according to + weights. Higher weight = more turns in the cycle. Example: weights 3 vs 1 = + ~75% vs ~25% of requests. + - `LEAST_CONNECTIONS`: Sends new connections to the member with fewest active + connections, performing round-robin within groups of the same normalized load. + Higher weight = allowed to hold more simultaneous connections before being + considered 'more loaded'. Example: weights 2 vs 1 means 20 vs 10 active + connections is treated as balanced. + - `SOURCE_IP`: Routes clients consistently to the same member by hashing client + source IP; hash result is modulo total weight of running members. Higher + weight = more hash buckets, so more client IPs map to that member. Example: + weights 2 vs 1 = roughly two-thirds of distinct client IPs map to the + higher-weight member. + """ + + +class SessionPersistence(TypedDict, total=False): + """New session persistence settings""" + + type: Required[LbSessionPersistenceType] + """Session persistence type""" + + cookie_name: Optional[str] + """Should be set if app cookie or http cookie is used""" + + persistence_granularity: Optional[str] + """Subnet mask if `source_ip` is used. For UDP ports only""" + + persistence_timeout: Optional[int] + """Session persistence timeout. For UDP ports only""" diff --git a/src/gcore/types/cloud/load_balancers/pools/__init__.py b/src/gcore/types/cloud/load_balancers/pools/__init__.py new file mode 100644 index 00000000..9eff4e72 --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/pools/__init__.py @@ -0,0 +1,6 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .member_create_params import MemberCreateParams as MemberCreateParams +from .health_monitor_create_params import HealthMonitorCreateParams as HealthMonitorCreateParams diff --git a/src/gcore/types/cloud/load_balancers/pools/health_monitor_create_params.py b/src/gcore/types/cloud/load_balancers/pools/health_monitor_create_params.py new file mode 100644 index 00000000..a1cabcbe --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/pools/health_monitor_create_params.py @@ -0,0 +1,63 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, Annotated, TypedDict + +from ....._utils import PropertyInfo +from ...http_method import HTTPMethod +from ...lb_health_monitor_type import LbHealthMonitorType + +__all__ = ["HealthMonitorCreateParams"] + + +class HealthMonitorCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + delay: Required[int] + """The time, in seconds, between sending probes to members""" + + max_retries: Required[int] + """Number of successes before the member is switched to ONLINE state""" + + api_timeout: Required[Annotated[int, PropertyInfo(alias="timeout")]] + """The maximum time to connect. Must be less than the delay value""" + + type: Required[LbHealthMonitorType] + """Health monitor type. Once health monitor is created, cannot be changed.""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + expected_codes: Optional[str] + """Expected HTTP response codes. + + Can be a single code or a range of codes. Can only be used together with `HTTP` + or `HTTPS` health monitor type. For example, + 200,202,300-302,401,403,404,500-504. If not specified, the default is 200. + """ + + http_method: Optional[HTTPMethod] + """HTTP method. + + Can only be used together with `HTTP` or `HTTPS` health monitor type. + """ + + max_retries_down: int + """Number of failures before the member is switched to ERROR state.""" + + url_path: Optional[str] + """URL Path. + + Defaults to '/'. Can only be used together with `HTTP` or `HTTPS` health monitor + type. + """ diff --git a/src/gcore/types/cloud/load_balancers/pools/member_create_params.py b/src/gcore/types/cloud/load_balancers/pools/member_create_params.py new file mode 100644 index 00000000..b05d79d6 --- /dev/null +++ b/src/gcore/types/cloud/load_balancers/pools/member_create_params.py @@ -0,0 +1,79 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +__all__ = ["MemberCreateParams"] + + +class MemberCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + address: Required[str] + """Member IP address""" + + protocol_port: Required[int] + """Member IP port""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + backup: bool + """ + Set to true if the member is a backup member, to which traffic will be sent + exclusively when all non-backup members will be unreachable. It allows to + realize ACTIVE-BACKUP load balancing without thinking about VRRP and VIP + configuration. Default is false. + """ + + instance_id: Optional[str] + """Either `subnet_id` or `instance_id` should be provided""" + + monitor_address: Optional[str] + """An alternate IP address used for health monitoring of a backend member. + + Default is null which monitors the member address. + """ + + monitor_port: Optional[int] + """An alternate protocol port used for health monitoring of a backend member. + + Default is null which monitors the member `protocol_port`. + """ + + subnet_id: Optional[str] + """`subnet_id` in which `address` is present. + + Either `subnet_id` or `instance_id` should be provided + """ + + weight: int + """Member weight. + + Valid values are 0 < `weight` <= 256, defaults to 1. Controls traffic + distribution based on the pool's load balancing algorithm: + + - `ROUND_ROBIN`: Distributes connections to each member in turn according to + weights. Higher weight = more turns in the cycle. Example: weights 3 vs 1 = + ~75% vs ~25% of requests. + - `LEAST_CONNECTIONS`: Sends new connections to the member with fewest active + connections, performing round-robin within groups of the same normalized load. + Higher weight = allowed to hold more simultaneous connections before being + considered 'more loaded'. Example: weights 2 vs 1 means 20 vs 10 active + connections is treated as balanced. + - `SOURCE_IP`: Routes clients consistently to the same member by hashing client + source IP; hash result is modulo total weight of running members. Higher + weight = more hash buckets, so more client IPs map to that member. Example: + weights 2 vs 1 = roughly two-thirds of distinct client IPs map to the + higher-weight member. + """ diff --git a/src/gcore/types/cloud/logging.py b/src/gcore/types/cloud/logging.py new file mode 100644 index 00000000..c9062e7e --- /dev/null +++ b/src/gcore/types/cloud/logging.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .laas_index_retention_policy import LaasIndexRetentionPolicy + +__all__ = ["Logging"] + + +class Logging(BaseModel): + destination_region_id: Optional[int] = None + """ID of the region in which the logs will be stored""" + + enabled: bool + """Indicates if log streaming is enabled or disabled""" + + topic_name: Optional[str] = None + """The topic name to stream logs to""" + + retention_policy: Optional[LaasIndexRetentionPolicy] = None + """Logs retention policy""" diff --git a/src/gcore/types/cloud/member.py b/src/gcore/types/cloud/member.py new file mode 100644 index 00000000..c9e2fc0d --- /dev/null +++ b/src/gcore/types/cloud/member.py @@ -0,0 +1,77 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .provisioning_status import ProvisioningStatus +from .load_balancer_operating_status import LoadBalancerOperatingStatus + +__all__ = ["Member"] + + +class Member(BaseModel): + id: str + """Member ID must be provided if an existing member is being updated""" + + address: str + """Member IP address""" + + admin_state_up: bool + """Administrative state of the resource. + + When set to true, the resource is enabled and operational. When set to false, + the resource is disabled and will not process traffic. Defaults to true. + """ + + backup: bool + """ + Set to true if the member is a backup member, to which traffic will be sent + exclusively when all non-backup members will be unreachable. It allows to + realize ACTIVE-BACKUP load balancing without thinking about VRRP and VIP + configuration. Default is false + """ + + operating_status: LoadBalancerOperatingStatus + """Member operating status of the entity""" + + protocol_port: int + """Member IP port""" + + provisioning_status: ProvisioningStatus + """Pool member lifecycle status""" + + subnet_id: Optional[str] = None + """`subnet_id` in which `address` is present.""" + + weight: int + """Member weight. + + Valid values are 0 < `weight` <= 256, defaults to 1. Controls traffic + distribution based on the pool's load balancing algorithm: + + - `ROUND_ROBIN`: Distributes connections to each member in turn according to + weights. Higher weight = more turns in the cycle. Example: weights 3 vs 1 = + ~75% vs ~25% of requests. + - `LEAST_CONNECTIONS`: Sends new connections to the member with fewest active + connections, performing round-robin within groups of the same normalized load. + Higher weight = allowed to hold more simultaneous connections before being + considered 'more loaded'. Example: weights 2 vs 1 means 20 vs 10 active + connections is treated as balanced. + - `SOURCE_IP`: Routes clients consistently to the same member by hashing client + source IP; hash result is modulo total weight of running members. Higher + weight = more hash buckets, so more client IPs map to that member. Example: + weights 2 vs 1 = roughly two-thirds of distinct client IPs map to the + higher-weight member. + """ + + monitor_address: Optional[str] = None + """An alternate IP address used for health monitoring of a backend member. + + Default is null which monitors the member address. + """ + + monitor_port: Optional[int] = None + """An alternate protocol port used for health monitoring of a backend member. + + Default is null which monitors the member `protocol_port`. + """ diff --git a/src/gcore/types/cloud/member_status.py b/src/gcore/types/cloud/member_status.py new file mode 100644 index 00000000..102424ae --- /dev/null +++ b/src/gcore/types/cloud/member_status.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel +from .provisioning_status import ProvisioningStatus +from .load_balancer_operating_status import LoadBalancerOperatingStatus + +__all__ = ["MemberStatus"] + + +class MemberStatus(BaseModel): + id: str + """UUID of the entity""" + + address: str + """Address of the member (server)""" + + operating_status: LoadBalancerOperatingStatus + """Operating status of the entity""" + + protocol_port: int + """Port of the member (server)""" + + provisioning_status: ProvisioningStatus + """Provisioning status of the entity""" diff --git a/src/gcore/types/cloud/network.py b/src/gcore/types/cloud/network.py new file mode 100644 index 00000000..71f16653 --- /dev/null +++ b/src/gcore/types/cloud/network.py @@ -0,0 +1,79 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from .tag import Tag +from ..._models import BaseModel + +__all__ = ["Network"] + + +class Network(BaseModel): + id: str + """Network ID""" + + created_at: datetime + """Datetime when the network was created""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + default: Optional[bool] = None + """True if network has `is_default` attribute""" + + external: bool + """True if the network `router:external` attribute""" + + mtu: int + """MTU (maximum transmission unit). Default value is 1450""" + + name: str + """Network name""" + + port_security_enabled: bool + """ + Indicates `port_security_enabled` status of all newly created in the network + ports. + """ + + project_id: Optional[int] = None + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + segmentation_id: Optional[int] = None + """Id of network segment""" + + shared: bool + """True when the network is shared with your project by external owner""" + + subnets: List[str] + """List of subnetworks""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + type: str + """Network type (vlan, vxlan)""" + + updated_at: datetime + """Datetime when the network was last updated""" diff --git a/src/gcore/types/cloud/network_create_params.py b/src/gcore/types/cloud/network_create_params.py new file mode 100644 index 00000000..935f9bc0 --- /dev/null +++ b/src/gcore/types/cloud/network_create_params.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["NetworkCreateParams"] + + +class NetworkCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: Required[str] + """Network name""" + + create_router: bool + """Defaults to True""" + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + type: Literal["vlan", "vxlan"] + """vlan or vxlan network type is allowed. Default value is vxlan""" diff --git a/src/gcore/types/cloud/network_details.py b/src/gcore/types/cloud/network_details.py new file mode 100644 index 00000000..1e0ad7cf --- /dev/null +++ b/src/gcore/types/cloud/network_details.py @@ -0,0 +1,80 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from .tag import Tag +from .subnet import Subnet +from ..._models import BaseModel + +__all__ = ["NetworkDetails"] + + +class NetworkDetails(BaseModel): + id: str + """Network ID""" + + created_at: datetime + """Datetime when the network was created""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + default: Optional[bool] = None + """True if network has `is_default` attribute""" + + external: bool + """True if the network `router:external` attribute""" + + mtu: int + """MTU (maximum transmission unit). Default value is 1450""" + + name: str + """Network name""" + + port_security_enabled: bool + """ + Indicates `port_security_enabled` status of all newly created in the network + ports. + """ + + project_id: Optional[int] = None + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + segmentation_id: Optional[int] = None + """Id of network segment""" + + shared: bool + """True when the network is shared with your project by external owner""" + + subnets: List[Subnet] + """List of subnets associated with the network""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + type: str + """Network type (vlan, vxlan)""" + + updated_at: datetime + """Datetime when the network was last updated""" diff --git a/src/gcore/types/cloud/network_interface.py b/src/gcore/types/cloud/network_interface.py new file mode 100644 index 00000000..ee262b28 --- /dev/null +++ b/src/gcore/types/cloud/network_interface.py @@ -0,0 +1,78 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .floating_ip import FloatingIP +from .ip_assignment import IPAssignment +from .network_details import NetworkDetails +from .allowed_address_pairs import AllowedAddressPairs + +__all__ = ["NetworkInterface", "SubPort"] + + +class SubPort(BaseModel): + allowed_address_pairs: List[AllowedAddressPairs] + """Group of subnet masks and/or IP addresses that share the current IP as VIP""" + + floatingip_details: List[FloatingIP] + """Bodies of floating IPs that are NAT-ing IPs of this port""" + + ip_assignments: List[IPAssignment] + """IP addresses assigned to this port""" + + network_details: NetworkDetails + """Body of the network this port is attached to""" + + network_id: str + """ID of the network the port is attached to""" + + port_id: str + """ID of virtual ethernet port object""" + + port_security_enabled: bool + """Port security status""" + + segmentation_id: int + """id of network segment""" + + segmentation_type: str + """type of network segment""" + + interface_name: Optional[str] = None + """Interface name""" + + mac_address: Optional[str] = None + """MAC address of the virtual port""" + + +class NetworkInterface(BaseModel): + allowed_address_pairs: List[AllowedAddressPairs] + """Group of subnet masks and/or IP addresses that share the current IP as VIP""" + + floatingip_details: List[FloatingIP] + """Bodies of floating IPs that are NAT-ing IPs of this port""" + + ip_assignments: List[IPAssignment] + """IP addresses assigned to this port""" + + network_details: NetworkDetails + """Body of the network this port is attached to""" + + network_id: str + """ID of the network the port is attached to""" + + port_id: str + """ID of virtual ethernet port object""" + + port_security_enabled: bool + """Port security status""" + + sub_ports: List[SubPort] + """body of ports that are included into trunk port""" + + interface_name: Optional[str] = None + """Interface name""" + + mac_address: Optional[str] = None + """MAC address of the virtual port""" diff --git a/src/gcore/types/cloud/network_interface_list.py b/src/gcore/types/cloud/network_interface_list.py new file mode 100644 index 00000000..42be30e6 --- /dev/null +++ b/src/gcore/types/cloud/network_interface_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .network_interface import NetworkInterface + +__all__ = ["NetworkInterfaceList"] + + +class NetworkInterfaceList(BaseModel): + count: int + """Number of objects""" + + results: List[NetworkInterface] + """Objects""" diff --git a/src/gcore/types/cloud/network_list_params.py b/src/gcore/types/cloud/network_list_params.py new file mode 100644 index 00000000..a690ab5b --- /dev/null +++ b/src/gcore/types/cloud/network_list_params.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["NetworkListParams"] + + +class NetworkListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + limit: int + """Optional. Limit the number of returned items""" + + name: str + """Filter networks by name""" + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ + + order_by: Literal["created_at.asc", "created_at.desc", "name.asc", "name.desc"] + """ + Ordering networks list result by `name`, `created_at` fields of the network and + directions (`created_at.desc`). + """ + + tag_key: SequenceNotStr[str] + """Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2""" + + tag_key_value: str + """Optional. Filter by tag key-value pairs.""" diff --git a/src/gcore/types/cloud/network_update_params.py b/src/gcore/types/cloud/network_update_params.py new file mode 100644 index 00000000..ab91fcf7 --- /dev/null +++ b/src/gcore/types/cloud/network_update_params.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +from .tag_update_map_param import TagUpdateMapParam + +__all__ = ["NetworkUpdateParams"] + + +class NetworkUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: str + """Name.""" + + tags: Optional[TagUpdateMapParam] + """Update key-value tags using JSON Merge Patch semantics (RFC 7386). + + Provide key-value pairs to add or update tags. Set tag values to `null` to + remove tags. Unspecified tags remain unchanged. Read-only tags are always + preserved and cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + """ diff --git a/src/gcore/types/cloud/networks/__init__.py b/src/gcore/types/cloud/networks/__init__.py new file mode 100644 index 00000000..be19f7cf --- /dev/null +++ b/src/gcore/types/cloud/networks/__init__.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .router import Router as Router +from .router_list import RouterList as RouterList +from .router_list_params import RouterListParams as RouterListParams +from .subnet_list_params import SubnetListParams as SubnetListParams +from .router_create_params import RouterCreateParams as RouterCreateParams +from .router_update_params import RouterUpdateParams as RouterUpdateParams +from .subnet_create_params import SubnetCreateParams as SubnetCreateParams +from .subnet_update_params import SubnetUpdateParams as SubnetUpdateParams +from .router_attach_subnet_params import RouterAttachSubnetParams as RouterAttachSubnetParams +from .router_detach_subnet_params import RouterDetachSubnetParams as RouterDetachSubnetParams diff --git a/src/gcore/types/cloud/networks/router.py b/src/gcore/types/cloud/networks/router.py new file mode 100644 index 00000000..5f7cac6b --- /dev/null +++ b/src/gcore/types/cloud/networks/router.py @@ -0,0 +1,85 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from ..route import Route +from ...._models import BaseModel +from ..ip_assignment import IPAssignment + +__all__ = ["Router", "Interface", "ExternalGatewayInfo"] + + +class Interface(BaseModel): + ip_assignments: List[IPAssignment] + """IP addresses assigned to this port""" + + network_id: str + """ID of the network the port is attached to""" + + port_id: str + """ID of virtual ethernet port object""" + + mac_address: Optional[str] = None + """MAC address of the virtual port""" + + +class ExternalGatewayInfo(BaseModel): + """State of this router's external gateway.""" + + enable_snat: bool + """Is SNAT enabled.""" + + external_fixed_ips: List[IPAssignment] + """List of external IPs that emit SNAT-ed traffic.""" + + network_id: str + """Id of the external network.""" + + +class Router(BaseModel): + id: str + """Router ID""" + + created_at: datetime + """Datetime when the router was created""" + + distributed: bool + """Whether the router is distributed or centralized.""" + + interfaces: List[Interface] + """List of router interfaces.""" + + name: str + """Router name""" + + project_id: int + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + routes: List[Route] + """List of custom routes.""" + + status: str + """Status of the router.""" + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + updated_at: datetime + """Datetime when the router was last updated""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + external_gateway_info: Optional[ExternalGatewayInfo] = None + """State of this router's external gateway.""" diff --git a/src/gcore/types/cloud/networks/router_attach_subnet_params.py b/src/gcore/types/cloud/networks/router_attach_subnet_params.py new file mode 100644 index 00000000..3ee5f7f6 --- /dev/null +++ b/src/gcore/types/cloud/networks/router_attach_subnet_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RouterAttachSubnetParams"] + + +class RouterAttachSubnetParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + subnet_id: Required[str] + """Subnet ID on which router interface will be created""" + + ip_address: str + """ + IP address to assign for router's interface, if not specified, address will be + selected automatically + """ diff --git a/src/gcore/types/cloud/networks/router_create_params.py b/src/gcore/types/cloud/networks/router_create_params.py new file mode 100644 index 00000000..4fa5449b --- /dev/null +++ b/src/gcore/types/cloud/networks/router_create_params.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "RouterCreateParams", + "ExternalGatewayInfo", + "ExternalGatewayInfoRouterExternalManualGwSerializer", + "ExternalGatewayInfoRouterExternalDefaultGwSerializer", + "Interface", + "Route", +] + + +class RouterCreateParams(TypedDict, total=False): + project_id: int + + region_id: int + + name: Required[str] + """name of router""" + + external_gateway_info: Optional[ExternalGatewayInfo] + + interfaces: Optional[Iterable[Interface]] + """List of interfaces to attach to router immediately after creation.""" + + routes: Optional[Iterable[Route]] + """List of custom routes.""" + + +class ExternalGatewayInfoRouterExternalManualGwSerializer(TypedDict, total=False): + network_id: Required[str] + """id of the external network.""" + + enable_snat: bool + """Is SNAT enabled. Defaults to true.""" + + type: Literal["manual"] + """must be 'manual'.""" + + +class ExternalGatewayInfoRouterExternalDefaultGwSerializer(TypedDict, total=False): + enable_snat: bool + """Is SNAT enabled. Defaults to true.""" + + type: Literal["default"] + """must be 'default'.""" + + +ExternalGatewayInfo: TypeAlias = Union[ + ExternalGatewayInfoRouterExternalManualGwSerializer, ExternalGatewayInfoRouterExternalDefaultGwSerializer +] + + +class Interface(TypedDict, total=False): + subnet_id: Required[str] + """id of the subnet to attach to.""" + + type: Literal["subnet"] + """must be 'subnet'.""" + + +class Route(TypedDict, total=False): + destination: Required[str] + """CIDR of destination IPv4 subnet.""" + + nexthop: Required[str] + """ + IPv4 address to forward traffic to if it's destination IP matches 'destination' + CIDR. + """ diff --git a/src/gcore/types/cloud/networks/router_detach_subnet_params.py b/src/gcore/types/cloud/networks/router_detach_subnet_params.py new file mode 100644 index 00000000..ecf64cb2 --- /dev/null +++ b/src/gcore/types/cloud/networks/router_detach_subnet_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RouterDetachSubnetParams"] + + +class RouterDetachSubnetParams(TypedDict, total=False): + project_id: int + + region_id: int + + subnet_id: Required[str] + """Target IP is identified by it's subnet""" diff --git a/src/gcore/types/cloud/networks/router_list.py b/src/gcore/types/cloud/networks/router_list.py new file mode 100644 index 00000000..23a83fc8 --- /dev/null +++ b/src/gcore/types/cloud/networks/router_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from .router import Router +from ...._models import BaseModel + +__all__ = ["RouterList"] + + +class RouterList(BaseModel): + count: int + """Number of objects""" + + results: List[Router] + """Objects""" diff --git a/src/gcore/types/cloud/networks/router_list_params.py b/src/gcore/types/cloud/networks/router_list_params.py new file mode 100644 index 00000000..4842c311 --- /dev/null +++ b/src/gcore/types/cloud/networks/router_list_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["RouterListParams"] + + +class RouterListParams(TypedDict, total=False): + project_id: int + + region_id: int + + limit: int + """Limit the number of returned routers""" + + offset: int + """Offset value is used to exclude the first set of records from the result""" diff --git a/src/gcore/types/cloud/networks/router_update_params.py b/src/gcore/types/cloud/networks/router_update_params.py new file mode 100644 index 00000000..44e4f142 --- /dev/null +++ b/src/gcore/types/cloud/networks/router_update_params.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RouterUpdateParams", "ExternalGatewayInfo", "Route"] + + +class RouterUpdateParams(TypedDict, total=False): + project_id: int + + region_id: int + + external_gateway_info: Optional[ExternalGatewayInfo] + """New external gateway.""" + + name: Optional[str] + """New name of router""" + + routes: Optional[Iterable[Route]] + """List of custom routes.""" + + +class ExternalGatewayInfo(TypedDict, total=False): + """New external gateway.""" + + network_id: Required[str] + """id of the external network.""" + + enable_snat: bool + """Is SNAT enabled. Defaults to true.""" + + type: Literal["manual"] + """must be 'manual'.""" + + +class Route(TypedDict, total=False): + destination: Required[str] + """CIDR of destination IPv4 subnet.""" + + nexthop: Required[str] + """ + IPv4 address to forward traffic to if it's destination IP matches 'destination' + CIDR. + """ diff --git a/src/gcore/types/cloud/networks/subnet_create_params.py b/src/gcore/types/cloud/networks/subnet_create_params.py new file mode 100644 index 00000000..41274927 --- /dev/null +++ b/src/gcore/types/cloud/networks/subnet_create_params.py @@ -0,0 +1,82 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Required, TypedDict + +from ...._types import SequenceNotStr +from ..ip_version import IPVersion + +__all__ = ["SubnetCreateParams", "HostRoute"] + + +class SubnetCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + cidr: Required[str] + """CIDR""" + + name: Required[str] + """Subnet name""" + + network_id: Required[str] + """Network ID""" + + connect_to_network_router: bool + """True if the network's router should get a gateway in this subnet. + + Must be explicitly 'false' when `gateway_ip` is null. + """ + + dns_nameservers: Optional[SequenceNotStr[str]] + """List IP addresses of DNS servers to advertise via DHCP.""" + + enable_dhcp: bool + """True if DHCP should be enabled""" + + gateway_ip: Optional[str] + """Default GW IPv4 address to advertise in DHCP routes in this subnet. + + Omit this field to let the cloud backend allocate it automatically. Set to null + if no gateway must be advertised by this subnet's DHCP (useful when attaching + instances to multiple subnets in order to prevent default route conflicts). + """ + + host_routes: Optional[Iterable[HostRoute]] + """List of custom static routes to advertise via DHCP.""" + + ip_version: IPVersion + """IP version""" + + router_id_to_connect: Optional[str] + """ID of the router to connect to. + + Requires `connect_to_network_router` set to true. If not specified, attempts to + find a router created during network creation. + """ + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + +class HostRoute(TypedDict, total=False): + destination: Required[str] + """CIDR of destination IPv4 subnet.""" + + nexthop: Required[str] + """ + IPv4 address to forward traffic to if it's destination IP matches 'destination' + CIDR. + """ diff --git a/src/gcore/types/cloud/networks/subnet_list_params.py b/src/gcore/types/cloud/networks/subnet_list_params.py new file mode 100644 index 00000000..4327998f --- /dev/null +++ b/src/gcore/types/cloud/networks/subnet_list_params.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["SubnetListParams"] + + +class SubnetListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + limit: int + """Optional. Limit the number of returned items""" + + network_id: str + """Only list subnets of this network""" + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ + + order_by: Literal[ + "available_ips.asc", + "available_ips.desc", + "cidr.asc", + "cidr.desc", + "created_at.asc", + "created_at.desc", + "name.asc", + "name.desc", + "total_ips.asc", + "total_ips.desc", + "updated_at.asc", + "updated_at.desc", + ] + """ + Ordering subnets list result by `name`, `created_at`, `updated_at`, + `available_ips`, `total_ips`, and `cidr` (default) fields of the subnet and + directions (`name.asc`). + """ + + tag_key: SequenceNotStr[str] + """Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2""" + + tag_key_value: str + """Optional. Filter by tag key-value pairs.""" diff --git a/src/gcore/types/cloud/networks/subnet_update_params.py b/src/gcore/types/cloud/networks/subnet_update_params.py new file mode 100644 index 00000000..d7a68399 --- /dev/null +++ b/src/gcore/types/cloud/networks/subnet_update_params.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Required, TypedDict + +from ...._types import SequenceNotStr +from ..tag_update_map_param import TagUpdateMapParam + +__all__ = ["SubnetUpdateParams", "HostRoute"] + + +class SubnetUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + dns_nameservers: Optional[SequenceNotStr[str]] + """List IP addresses of DNS servers to advertise via DHCP.""" + + enable_dhcp: bool + """True if DHCP should be enabled""" + + gateway_ip: Optional[str] + """Default GW IPv4 address to advertise in DHCP routes in this subnet. + + Omit this field to let the cloud backend allocate it automatically. Set to null + if no gateway must be advertised by this subnet's DHCP (useful when attaching + instances to multiple subnets in order to prevent default route conflicts). + """ + + host_routes: Optional[Iterable[HostRoute]] + """List of custom static routes to advertise via DHCP.""" + + name: Optional[str] + """Name""" + + tags: Optional[TagUpdateMapParam] + """Update key-value tags using JSON Merge Patch semantics (RFC 7386). + + Provide key-value pairs to add or update tags. Set tag values to `null` to + remove tags. Unspecified tags remain unchanged. Read-only tags are always + preserved and cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + """ + + +class HostRoute(TypedDict, total=False): + destination: Required[str] + """CIDR of destination IPv4 subnet.""" + + nexthop: Required[str] + """ + IPv4 address to forward traffic to if it's destination IP matches 'destination' + CIDR. + """ diff --git a/src/gcore/types/cloud/placement_group.py b/src/gcore/types/cloud/placement_group.py new file mode 100644 index 00000000..64c528a0 --- /dev/null +++ b/src/gcore/types/cloud/placement_group.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel + +__all__ = ["PlacementGroup", "Instance"] + + +class Instance(BaseModel): + instance_id: str + """The ID of the instance, corresponding to the attribute 'id'.""" + + instance_name: str + """The name of the instance, corresponding to the attribute 'name'.""" + + +class PlacementGroup(BaseModel): + instances: List[Instance] + """The list of instances in this server group.""" + + name: str + """The name of the server group.""" + + policy: str + """The server group policy. + + Options are: anti-affinity, affinity, or soft-anti-affinity. + """ + + project_id: int + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + servergroup_id: str + """The ID of the server group.""" diff --git a/src/gcore/types/cloud/placement_group_create_params.py b/src/gcore/types/cloud/placement_group_create_params.py new file mode 100644 index 00000000..b5ca3e39 --- /dev/null +++ b/src/gcore/types/cloud/placement_group_create_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["PlacementGroupCreateParams"] + + +class PlacementGroupCreateParams(TypedDict, total=False): + project_id: int + + region_id: int + + name: Required[str] + """The name of the server group.""" + + policy: Required[Literal["affinity", "anti-affinity", "soft-anti-affinity"]] + """The server group policy.""" diff --git a/src/gcore/types/cloud/placement_group_list.py b/src/gcore/types/cloud/placement_group_list.py new file mode 100644 index 00000000..92fbc1f9 --- /dev/null +++ b/src/gcore/types/cloud/placement_group_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .placement_group import PlacementGroup + +__all__ = ["PlacementGroupList"] + + +class PlacementGroupList(BaseModel): + count: int + """Number of objects""" + + results: List[PlacementGroup] + """Objects""" diff --git a/src/gcore/types/cloud/pool_status.py b/src/gcore/types/cloud/pool_status.py new file mode 100644 index 00000000..0af514bc --- /dev/null +++ b/src/gcore/types/cloud/pool_status.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .member_status import MemberStatus +from .provisioning_status import ProvisioningStatus +from .health_monitor_status import HealthMonitorStatus +from .load_balancer_operating_status import LoadBalancerOperatingStatus + +__all__ = ["PoolStatus"] + + +class PoolStatus(BaseModel): + id: str + """UUID of the entity""" + + members: List[MemberStatus] + """Members (servers) of the pool""" + + name: str + """Name of the load balancer pool""" + + operating_status: LoadBalancerOperatingStatus + """Operating status of the entity""" + + provisioning_status: ProvisioningStatus + """Provisioning status of the entity""" + + health_monitor: Optional[HealthMonitorStatus] = None + """Health Monitor of the Pool""" diff --git a/src/gcore/types/cloud/project.py b/src/gcore/types/cloud/project.py new file mode 100644 index 00000000..ce547c1a --- /dev/null +++ b/src/gcore/types/cloud/project.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["Project"] + + +class Project(BaseModel): + id: int + """Project ID, which is automatically generated upon creation.""" + + client_id: int + """ID associated with the client.""" + + created_at: datetime + """Datetime of creation, which is automatically generated.""" + + deleted_at: Optional[datetime] = None + """ + Datetime of deletion, which is automatically generated if the project is + deleted. + """ + + description: Optional[str] = None + """Description of the project.""" + + is_default: bool + """Indicates if the project is the default one. + + Each client always has one default project. + """ + + name: str + """Unique project name for a client.""" + + state: str + """The state of the project.""" + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ diff --git a/src/gcore/types/cloud/project_create_params.py b/src/gcore/types/cloud/project_create_params.py new file mode 100644 index 00000000..86a3ff86 --- /dev/null +++ b/src/gcore/types/cloud/project_create_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +__all__ = ["ProjectCreateParams"] + + +class ProjectCreateParams(TypedDict, total=False): + name: Required[str] + """Unique project name for a client. Each client always has one "default" project.""" + + description: Optional[str] + """Description of the project.""" diff --git a/src/gcore/types/cloud/project_list_params.py b/src/gcore/types/cloud/project_list_params.py new file mode 100644 index 00000000..a469a6ed --- /dev/null +++ b/src/gcore/types/cloud/project_list_params.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["ProjectListParams"] + + +class ProjectListParams(TypedDict, total=False): + client_id: int + """Client ID filter for administrators.""" + + include_deleted: bool + """Whether to include deleted projects in the response.""" + + limit: int + """Limit value is used to limit the number of records in the result""" + + name: str + """Name to filter the results by.""" + + offset: int + """Offset value is used to exclude the first set of records from the result""" + + order_by: Literal["created_at.asc", "created_at.desc", "name.asc", "name.desc"] + """Order by field and direction.""" diff --git a/src/gcore/types/cloud/project_update_params.py b/src/gcore/types/cloud/project_update_params.py new file mode 100644 index 00000000..ee0861f6 --- /dev/null +++ b/src/gcore/types/cloud/project_update_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ProjectUpdateParams"] + + +class ProjectUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + description: str + """Description of the project.""" + + name: str + """Name of the entity, following a specific format.""" diff --git a/src/gcore/types/cloud/provisioning_status.py b/src/gcore/types/cloud/provisioning_status.py new file mode 100644 index 00000000..5b2977b3 --- /dev/null +++ b/src/gcore/types/cloud/provisioning_status.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["ProvisioningStatus"] + +ProvisioningStatus: TypeAlias = Literal[ + "ACTIVE", "DELETED", "ERROR", "PENDING_CREATE", "PENDING_DELETE", "PENDING_UPDATE" +] diff --git a/src/gcore/types/cloud/quota_get_all_response.py b/src/gcore/types/cloud/quota_get_all_response.py new file mode 100644 index 00000000..019ceacf --- /dev/null +++ b/src/gcore/types/cloud/quota_get_all_response.py @@ -0,0 +1,382 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["QuotaGetAllResponse", "GlobalQuotas", "RegionalQuota"] + + +class GlobalQuotas(BaseModel): + """Global entity quotas""" + + inference_cpu_millicore_count_limit: Optional[int] = None + """Inference CPU millicore count limit""" + + inference_cpu_millicore_count_usage: Optional[int] = None + """Inference CPU millicore count usage""" + + inference_gpu_a100_count_limit: Optional[int] = None + """Inference GPU A100 Count limit""" + + inference_gpu_a100_count_usage: Optional[int] = None + """Inference GPU A100 Count usage""" + + inference_gpu_h100_count_limit: Optional[int] = None + """Inference GPU H100 Count limit""" + + inference_gpu_h100_count_usage: Optional[int] = None + """Inference GPU H100 Count usage""" + + inference_gpu_l40s_count_limit: Optional[int] = None + """Inference GPU L40s Count limit""" + + inference_gpu_l40s_count_usage: Optional[int] = None + """Inference GPU L40s Count usage""" + + inference_instance_count_limit: Optional[int] = None + """Inference instance count limit""" + + inference_instance_count_usage: Optional[int] = None + """Inference instance count usage""" + + keypair_count_limit: Optional[int] = None + """SSH Keys Count limit""" + + keypair_count_usage: Optional[int] = None + """SSH Keys Count usage""" + + project_count_limit: Optional[int] = None + """Projects Count limit""" + + project_count_usage: Optional[int] = None + """Projects Count usage""" + + +class RegionalQuota(BaseModel): + baremetal_basic_count_limit: Optional[int] = None + """Basic bare metal servers count limit""" + + baremetal_basic_count_usage: Optional[int] = None + """Basic bare metal servers count usage""" + + baremetal_gpu_a100_count_limit: Optional[int] = None + """Bare metal A100 GPU server count limit""" + + baremetal_gpu_a100_count_usage: Optional[int] = None + """Bare metal A100 GPU server count usage""" + + baremetal_gpu_count_limit: Optional[int] = None + """Total number of AI GPU bare metal servers. + + This field is deprecated and is now always calculated automatically as the sum + of `baremetal_gpu_a100_count_limit`, `baremetal_gpu_h100_count_limit`, + `baremetal_gpu_h200_count_limit`, and `baremetal_gpu_l40s_count_limit`. + """ + + baremetal_gpu_count_usage: Optional[int] = None + """Baremetal Gpu Count Usage. + + This field is deprecated and is now always calculated automatically as the sum + of `baremetal_gpu_a100_count_usage`, `baremetal_gpu_h100_count_usage`, + `baremetal_gpu_h200_count_usage`, and `baremetal_gpu_l40s_count_usage`. + """ + + baremetal_gpu_h100_count_limit: Optional[int] = None + """Bare metal H100 GPU server count limit""" + + baremetal_gpu_h100_count_usage: Optional[int] = None + """Bare metal H100 GPU server count usage""" + + baremetal_gpu_h200_count_limit: Optional[int] = None + """Bare metal H200 GPU server count limit""" + + baremetal_gpu_h200_count_usage: Optional[int] = None + """Bare metal H200 GPU server count usage""" + + baremetal_gpu_l40s_count_limit: Optional[int] = None + """Bare metal L40S GPU server count limit""" + + baremetal_gpu_l40s_count_usage: Optional[int] = None + """Bare metal L40S GPU server count usage""" + + baremetal_hf_count_limit: Optional[int] = None + """High-frequency bare metal servers count limit""" + + baremetal_hf_count_usage: Optional[int] = None + """High-frequency bare metal servers count usage""" + + baremetal_infrastructure_count_limit: Optional[int] = None + """Infrastructure bare metal servers count limit""" + + baremetal_infrastructure_count_usage: Optional[int] = None + """Infrastructure bare metal servers count usage""" + + baremetal_network_count_limit: Optional[int] = None + """Bare metal Network Count limit""" + + baremetal_network_count_usage: Optional[int] = None + """Bare metal Network Count usage""" + + baremetal_storage_count_limit: Optional[int] = None + """Storage bare metal servers count limit""" + + baremetal_storage_count_usage: Optional[int] = None + """Storage bare metal servers count usage""" + + caas_container_count_limit: Optional[int] = None + """Containers count limit""" + + caas_container_count_usage: Optional[int] = None + """Containers count usage""" + + caas_cpu_count_limit: Optional[int] = None + """mCPU count for containers limit""" + + caas_cpu_count_usage: Optional[int] = None + """mCPU count for containers usage""" + + caas_gpu_count_limit: Optional[int] = None + """Containers gpu count limit""" + + caas_gpu_count_usage: Optional[int] = None + """Containers gpu count usage""" + + caas_ram_size_limit: Optional[int] = None + """MB memory count for containers limit""" + + caas_ram_size_usage: Optional[int] = None + """MB memory count for containers usage""" + + cluster_count_limit: Optional[int] = None + """K8s clusters count limit""" + + cluster_count_usage: Optional[int] = None + """K8s clusters count usage""" + + cpu_count_limit: Optional[int] = None + """vCPU Count limit""" + + cpu_count_usage: Optional[int] = None + """vCPU Count usage""" + + dbaas_postgres_cluster_count_limit: Optional[int] = None + """DBaaS cluster count limit""" + + dbaas_postgres_cluster_count_usage: Optional[int] = None + """DBaaS cluster count usage""" + + external_ip_count_limit: Optional[int] = None + """External IP Count limit""" + + external_ip_count_usage: Optional[int] = None + """External IP Count usage""" + + faas_cpu_count_limit: Optional[int] = None + """mCPU count for functions limit""" + + faas_cpu_count_usage: Optional[int] = None + """mCPU count for functions usage""" + + faas_function_count_limit: Optional[int] = None + """Functions count limit""" + + faas_function_count_usage: Optional[int] = None + """Functions count usage""" + + faas_namespace_count_limit: Optional[int] = None + """Functions namespace count limit""" + + faas_namespace_count_usage: Optional[int] = None + """Functions namespace count usage""" + + faas_ram_size_limit: Optional[int] = None + """MB memory count for functions limit""" + + faas_ram_size_usage: Optional[int] = None + """MB memory count for functions usage""" + + firewall_count_limit: Optional[int] = None + """Firewalls Count limit""" + + firewall_count_usage: Optional[int] = None + """Firewalls Count usage""" + + floating_count_limit: Optional[int] = None + """Floating IP Count limit""" + + floating_count_usage: Optional[int] = None + """Floating IP Count usage""" + + gpu_count_limit: Optional[int] = None + """GPU Count limit""" + + gpu_count_usage: Optional[int] = None + """GPU Count usage""" + + gpu_virtual_a100_count_limit: Optional[int] = None + """Virtual A100 GPU card count limit""" + + gpu_virtual_a100_count_usage: Optional[int] = None + """Virtual A100 GPU card count usage""" + + gpu_virtual_h100_count_limit: Optional[int] = None + """Virtual H100 GPU card count limit""" + + gpu_virtual_h100_count_usage: Optional[int] = None + """Virtual H100 GPU card count usage""" + + gpu_virtual_h200_count_limit: Optional[int] = None + """Virtual H200 GPU card count limit""" + + gpu_virtual_h200_count_usage: Optional[int] = None + """Virtual H200 GPU card count usage""" + + gpu_virtual_l40s_count_limit: Optional[int] = None + """Virtual L40S GPU card count limit""" + + gpu_virtual_l40s_count_usage: Optional[int] = None + """Virtual L40S GPU card count usage""" + + image_count_limit: Optional[int] = None + """Images Count limit""" + + image_count_usage: Optional[int] = None + """Images Count usage""" + + image_size_limit: Optional[int] = None + """Images Size, GiB limit""" + + image_size_usage: Optional[int] = None + """Images Size, GiB usage""" + + ipu_count_limit: Optional[int] = None + """IPU Count limit""" + + ipu_count_usage: Optional[int] = None + """IPU Count usage""" + + laas_topic_count_limit: Optional[int] = None + """LaaS Topics Count limit""" + + laas_topic_count_usage: Optional[int] = None + """LaaS Topics Count usage""" + + loadbalancer_count_limit: Optional[int] = None + """Load Balancers Count limit""" + + loadbalancer_count_usage: Optional[int] = None + """Load Balancers Count usage""" + + network_count_limit: Optional[int] = None + """Networks Count limit""" + + network_count_usage: Optional[int] = None + """Networks Count usage""" + + ram_limit: Optional[int] = None + """RAM Size, GiB limit""" + + ram_usage: Optional[int] = None + """RAM Size, GiB usage""" + + region_id: Optional[int] = None + """Region ID""" + + registry_count_limit: Optional[int] = None + """Registries count limit""" + + registry_count_usage: Optional[int] = None + """Registries count usage""" + + registry_storage_limit: Optional[int] = None + """Registries volume usage, GiB limit""" + + registry_storage_usage: Optional[int] = None + """Registries volume usage, GiB usage""" + + router_count_limit: Optional[int] = None + """Routers Count limit""" + + router_count_usage: Optional[int] = None + """Routers Count usage""" + + secret_count_limit: Optional[int] = None + """Secret Count limit""" + + secret_count_usage: Optional[int] = None + """Secret Count usage""" + + servergroup_count_limit: Optional[int] = None + """Placement Group Count limit""" + + servergroup_count_usage: Optional[int] = None + """Placement Group Count usage""" + + sfs_count_limit: Optional[int] = None + """Shared file system Count limit""" + + sfs_count_usage: Optional[int] = None + """Shared file system Count usage""" + + sfs_size_limit: Optional[int] = None + """Shared file system Size, GiB limit""" + + sfs_size_usage: Optional[int] = None + """Shared file system Size, GiB usage""" + + shared_vm_count_limit: Optional[int] = None + """Basic VMs Count limit""" + + shared_vm_count_usage: Optional[int] = None + """Basic VMs Count usage""" + + snapshot_schedule_count_limit: Optional[int] = None + """Snapshot Schedules Count limit""" + + snapshot_schedule_count_usage: Optional[int] = None + """Snapshot Schedules Count usage""" + + subnet_count_limit: Optional[int] = None + """Subnets Count limit""" + + subnet_count_usage: Optional[int] = None + """Subnets Count usage""" + + vm_count_limit: Optional[int] = None + """Instances Dedicated Count limit""" + + vm_count_usage: Optional[int] = None + """Instances Dedicated Count usage""" + + volume_count_limit: Optional[int] = None + """Volumes Count limit""" + + volume_count_usage: Optional[int] = None + """Volumes Count usage""" + + volume_size_limit: Optional[int] = None + """Volumes Size, GiB limit""" + + volume_size_usage: Optional[int] = None + """Volumes Size, GiB usage""" + + volume_snapshots_count_limit: Optional[int] = None + """Snapshots Count limit""" + + volume_snapshots_count_usage: Optional[int] = None + """Snapshots Count usage""" + + volume_snapshots_size_limit: Optional[int] = None + """Snapshots Size, GiB limit""" + + volume_snapshots_size_usage: Optional[int] = None + """Snapshots Size, GiB usage""" + + +class QuotaGetAllResponse(BaseModel): + global_quotas: Optional[GlobalQuotas] = None + """Global entity quotas""" + + regional_quotas: Optional[List[RegionalQuota]] = None + """Regional entity quotas. Only contains initialized quotas.""" diff --git a/src/gcore/types/cloud/quota_get_by_region_response.py b/src/gcore/types/cloud/quota_get_by_region_response.py new file mode 100644 index 00000000..aef7ba2b --- /dev/null +++ b/src/gcore/types/cloud/quota_get_by_region_response.py @@ -0,0 +1,328 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["QuotaGetByRegionResponse"] + + +class QuotaGetByRegionResponse(BaseModel): + baremetal_basic_count_limit: Optional[int] = None + """Basic bare metal servers count limit""" + + baremetal_basic_count_usage: Optional[int] = None + """Basic bare metal servers count usage""" + + baremetal_gpu_a100_count_limit: Optional[int] = None + """Bare metal A100 GPU server count limit""" + + baremetal_gpu_a100_count_usage: Optional[int] = None + """Bare metal A100 GPU server count usage""" + + baremetal_gpu_count_limit: Optional[int] = None + """Total number of AI GPU bare metal servers. + + This field is deprecated and is now always calculated automatically as the sum + of `baremetal_gpu_a100_count_limit`, `baremetal_gpu_h100_count_limit`, + `baremetal_gpu_h200_count_limit`, and `baremetal_gpu_l40s_count_limit`. + """ + + baremetal_gpu_count_usage: Optional[int] = None + """Baremetal Gpu Count Usage. + + This field is deprecated and is now always calculated automatically as the sum + of `baremetal_gpu_a100_count_usage`, `baremetal_gpu_h100_count_usage`, + `baremetal_gpu_h200_count_usage`, and `baremetal_gpu_l40s_count_usage`. + """ + + baremetal_gpu_h100_count_limit: Optional[int] = None + """Bare metal H100 GPU server count limit""" + + baremetal_gpu_h100_count_usage: Optional[int] = None + """Bare metal H100 GPU server count usage""" + + baremetal_gpu_h200_count_limit: Optional[int] = None + """Bare metal H200 GPU server count limit""" + + baremetal_gpu_h200_count_usage: Optional[int] = None + """Bare metal H200 GPU server count usage""" + + baremetal_gpu_l40s_count_limit: Optional[int] = None + """Bare metal L40S GPU server count limit""" + + baremetal_gpu_l40s_count_usage: Optional[int] = None + """Bare metal L40S GPU server count usage""" + + baremetal_hf_count_limit: Optional[int] = None + """High-frequency bare metal servers count limit""" + + baremetal_hf_count_usage: Optional[int] = None + """High-frequency bare metal servers count usage""" + + baremetal_infrastructure_count_limit: Optional[int] = None + """Infrastructure bare metal servers count limit""" + + baremetal_infrastructure_count_usage: Optional[int] = None + """Infrastructure bare metal servers count usage""" + + baremetal_network_count_limit: Optional[int] = None + """Bare metal Network Count limit""" + + baremetal_network_count_usage: Optional[int] = None + """Bare metal Network Count usage""" + + baremetal_storage_count_limit: Optional[int] = None + """Storage bare metal servers count limit""" + + baremetal_storage_count_usage: Optional[int] = None + """Storage bare metal servers count usage""" + + caas_container_count_limit: Optional[int] = None + """Containers count limit""" + + caas_container_count_usage: Optional[int] = None + """Containers count usage""" + + caas_cpu_count_limit: Optional[int] = None + """mCPU count for containers limit""" + + caas_cpu_count_usage: Optional[int] = None + """mCPU count for containers usage""" + + caas_gpu_count_limit: Optional[int] = None + """Containers gpu count limit""" + + caas_gpu_count_usage: Optional[int] = None + """Containers gpu count usage""" + + caas_ram_size_limit: Optional[int] = None + """MB memory count for containers limit""" + + caas_ram_size_usage: Optional[int] = None + """MB memory count for containers usage""" + + cluster_count_limit: Optional[int] = None + """K8s clusters count limit""" + + cluster_count_usage: Optional[int] = None + """K8s clusters count usage""" + + cpu_count_limit: Optional[int] = None + """vCPU Count limit""" + + cpu_count_usage: Optional[int] = None + """vCPU Count usage""" + + dbaas_postgres_cluster_count_limit: Optional[int] = None + """DBaaS cluster count limit""" + + dbaas_postgres_cluster_count_usage: Optional[int] = None + """DBaaS cluster count usage""" + + external_ip_count_limit: Optional[int] = None + """External IP Count limit""" + + external_ip_count_usage: Optional[int] = None + """External IP Count usage""" + + faas_cpu_count_limit: Optional[int] = None + """mCPU count for functions limit""" + + faas_cpu_count_usage: Optional[int] = None + """mCPU count for functions usage""" + + faas_function_count_limit: Optional[int] = None + """Functions count limit""" + + faas_function_count_usage: Optional[int] = None + """Functions count usage""" + + faas_namespace_count_limit: Optional[int] = None + """Functions namespace count limit""" + + faas_namespace_count_usage: Optional[int] = None + """Functions namespace count usage""" + + faas_ram_size_limit: Optional[int] = None + """MB memory count for functions limit""" + + faas_ram_size_usage: Optional[int] = None + """MB memory count for functions usage""" + + firewall_count_limit: Optional[int] = None + """Firewalls Count limit""" + + firewall_count_usage: Optional[int] = None + """Firewalls Count usage""" + + floating_count_limit: Optional[int] = None + """Floating IP Count limit""" + + floating_count_usage: Optional[int] = None + """Floating IP Count usage""" + + gpu_count_limit: Optional[int] = None + """GPU Count limit""" + + gpu_count_usage: Optional[int] = None + """GPU Count usage""" + + gpu_virtual_a100_count_limit: Optional[int] = None + """Virtual A100 GPU card count limit""" + + gpu_virtual_a100_count_usage: Optional[int] = None + """Virtual A100 GPU card count usage""" + + gpu_virtual_h100_count_limit: Optional[int] = None + """Virtual H100 GPU card count limit""" + + gpu_virtual_h100_count_usage: Optional[int] = None + """Virtual H100 GPU card count usage""" + + gpu_virtual_h200_count_limit: Optional[int] = None + """Virtual H200 GPU card count limit""" + + gpu_virtual_h200_count_usage: Optional[int] = None + """Virtual H200 GPU card count usage""" + + gpu_virtual_l40s_count_limit: Optional[int] = None + """Virtual L40S GPU card count limit""" + + gpu_virtual_l40s_count_usage: Optional[int] = None + """Virtual L40S GPU card count usage""" + + image_count_limit: Optional[int] = None + """Images Count limit""" + + image_count_usage: Optional[int] = None + """Images Count usage""" + + image_size_limit: Optional[int] = None + """Images Size, GiB limit""" + + image_size_usage: Optional[int] = None + """Images Size, GiB usage""" + + ipu_count_limit: Optional[int] = None + """IPU Count limit""" + + ipu_count_usage: Optional[int] = None + """IPU Count usage""" + + laas_topic_count_limit: Optional[int] = None + """LaaS Topics Count limit""" + + laas_topic_count_usage: Optional[int] = None + """LaaS Topics Count usage""" + + loadbalancer_count_limit: Optional[int] = None + """Load Balancers Count limit""" + + loadbalancer_count_usage: Optional[int] = None + """Load Balancers Count usage""" + + network_count_limit: Optional[int] = None + """Networks Count limit""" + + network_count_usage: Optional[int] = None + """Networks Count usage""" + + ram_limit: Optional[int] = None + """RAM Size, GiB limit""" + + ram_usage: Optional[int] = None + """RAM Size, GiB usage""" + + region_id: Optional[int] = None + """Region ID""" + + registry_count_limit: Optional[int] = None + """Registries count limit""" + + registry_count_usage: Optional[int] = None + """Registries count usage""" + + registry_storage_limit: Optional[int] = None + """Registries volume usage, GiB limit""" + + registry_storage_usage: Optional[int] = None + """Registries volume usage, GiB usage""" + + router_count_limit: Optional[int] = None + """Routers Count limit""" + + router_count_usage: Optional[int] = None + """Routers Count usage""" + + secret_count_limit: Optional[int] = None + """Secret Count limit""" + + secret_count_usage: Optional[int] = None + """Secret Count usage""" + + servergroup_count_limit: Optional[int] = None + """Placement Group Count limit""" + + servergroup_count_usage: Optional[int] = None + """Placement Group Count usage""" + + sfs_count_limit: Optional[int] = None + """Shared file system Count limit""" + + sfs_count_usage: Optional[int] = None + """Shared file system Count usage""" + + sfs_size_limit: Optional[int] = None + """Shared file system Size, GiB limit""" + + sfs_size_usage: Optional[int] = None + """Shared file system Size, GiB usage""" + + shared_vm_count_limit: Optional[int] = None + """Basic VMs Count limit""" + + shared_vm_count_usage: Optional[int] = None + """Basic VMs Count usage""" + + snapshot_schedule_count_limit: Optional[int] = None + """Snapshot Schedules Count limit""" + + snapshot_schedule_count_usage: Optional[int] = None + """Snapshot Schedules Count usage""" + + subnet_count_limit: Optional[int] = None + """Subnets Count limit""" + + subnet_count_usage: Optional[int] = None + """Subnets Count usage""" + + vm_count_limit: Optional[int] = None + """Instances Dedicated Count limit""" + + vm_count_usage: Optional[int] = None + """Instances Dedicated Count usage""" + + volume_count_limit: Optional[int] = None + """Volumes Count limit""" + + volume_count_usage: Optional[int] = None + """Volumes Count usage""" + + volume_size_limit: Optional[int] = None + """Volumes Size, GiB limit""" + + volume_size_usage: Optional[int] = None + """Volumes Size, GiB usage""" + + volume_snapshots_count_limit: Optional[int] = None + """Snapshots Count limit""" + + volume_snapshots_count_usage: Optional[int] = None + """Snapshots Count usage""" + + volume_snapshots_size_limit: Optional[int] = None + """Snapshots Size, GiB limit""" + + volume_snapshots_size_usage: Optional[int] = None + """Snapshots Size, GiB usage""" diff --git a/src/gcore/types/cloud/quota_get_global_response.py b/src/gcore/types/cloud/quota_get_global_response.py new file mode 100644 index 00000000..39773e14 --- /dev/null +++ b/src/gcore/types/cloud/quota_get_global_response.py @@ -0,0 +1,51 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["QuotaGetGlobalResponse"] + + +class QuotaGetGlobalResponse(BaseModel): + inference_cpu_millicore_count_limit: Optional[int] = None + """Inference CPU millicore count limit""" + + inference_cpu_millicore_count_usage: Optional[int] = None + """Inference CPU millicore count usage""" + + inference_gpu_a100_count_limit: Optional[int] = None + """Inference GPU A100 Count limit""" + + inference_gpu_a100_count_usage: Optional[int] = None + """Inference GPU A100 Count usage""" + + inference_gpu_h100_count_limit: Optional[int] = None + """Inference GPU H100 Count limit""" + + inference_gpu_h100_count_usage: Optional[int] = None + """Inference GPU H100 Count usage""" + + inference_gpu_l40s_count_limit: Optional[int] = None + """Inference GPU L40s Count limit""" + + inference_gpu_l40s_count_usage: Optional[int] = None + """Inference GPU L40s Count usage""" + + inference_instance_count_limit: Optional[int] = None + """Inference instance count limit""" + + inference_instance_count_usage: Optional[int] = None + """Inference instance count usage""" + + keypair_count_limit: Optional[int] = None + """SSH Keys Count limit""" + + keypair_count_usage: Optional[int] = None + """SSH Keys Count usage""" + + project_count_limit: Optional[int] = None + """Projects Count limit""" + + project_count_usage: Optional[int] = None + """Projects Count usage""" diff --git a/src/gcore/types/cloud/quotas/__init__.py b/src/gcore/types/cloud/quotas/__init__.py new file mode 100644 index 00000000..600a55cb --- /dev/null +++ b/src/gcore/types/cloud/quotas/__init__.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .request_list_params import RequestListParams as RequestListParams +from .request_get_response import RequestGetResponse as RequestGetResponse +from .request_create_params import RequestCreateParams as RequestCreateParams +from .request_list_response import RequestListResponse as RequestListResponse diff --git a/src/gcore/types/cloud/quotas/request_create_params.py b/src/gcore/types/cloud/quotas/request_create_params.py new file mode 100644 index 00000000..c6afc586 --- /dev/null +++ b/src/gcore/types/cloud/quotas/request_create_params.py @@ -0,0 +1,214 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["RequestCreateParams", "RequestedLimits", "RequestedLimitsGlobalLimits", "RequestedLimitsRegionalLimit"] + + +class RequestCreateParams(TypedDict, total=False): + description: Required[str] + """Describe the reason, in general terms.""" + + requested_limits: Required[RequestedLimits] + """Limits you want to increase.""" + + +class RequestedLimitsGlobalLimits(TypedDict, total=False): + """Global entity quota limits""" + + inference_cpu_millicore_count_limit: int + """Inference CPU millicore count limit""" + + inference_gpu_a100_count_limit: int + """Inference GPU A100 Count limit""" + + inference_gpu_h100_count_limit: int + """Inference GPU H100 Count limit""" + + inference_gpu_l40s_count_limit: int + """Inference GPU L40s Count limit""" + + inference_instance_count_limit: int + """Inference instance count limit""" + + keypair_count_limit: int + """SSH Keys Count limit""" + + project_count_limit: int + """Projects Count limit""" + + +class RequestedLimitsRegionalLimit(TypedDict, total=False): + baremetal_basic_count_limit: int + """Basic bare metal servers count limit""" + + baremetal_gpu_a100_count_limit: int + """Bare metal A100 GPU server count limit""" + + baremetal_gpu_count_limit: int + """Total number of AI GPU bare metal servers. + + This field is deprecated and is now always calculated automatically as the sum + of `baremetal_gpu_a100_count_limit`, `baremetal_gpu_h100_count_limit`, + `baremetal_gpu_h200_count_limit`, and `baremetal_gpu_l40s_count_limit`. + """ + + baremetal_gpu_h100_count_limit: int + """Bare metal H100 GPU server count limit""" + + baremetal_gpu_h200_count_limit: int + """Bare metal H200 GPU server count limit""" + + baremetal_gpu_l40s_count_limit: int + """Bare metal L40S GPU server count limit""" + + baremetal_hf_count_limit: int + """High-frequency bare metal servers count limit""" + + baremetal_infrastructure_count_limit: int + """Infrastructure bare metal servers count limit""" + + baremetal_network_count_limit: int + """Bare metal Network Count limit""" + + baremetal_storage_count_limit: int + """Storage bare metal servers count limit""" + + caas_container_count_limit: int + """Containers count limit""" + + caas_cpu_count_limit: int + """mCPU count for containers limit""" + + caas_gpu_count_limit: int + """Containers gpu count limit""" + + caas_ram_size_limit: int + """MB memory count for containers limit""" + + cluster_count_limit: int + """K8s clusters count limit""" + + cpu_count_limit: int + """vCPU Count limit""" + + dbaas_postgres_cluster_count_limit: int + """DBaaS cluster count limit""" + + external_ip_count_limit: int + """External IP Count limit""" + + faas_cpu_count_limit: int + """mCPU count for functions limit""" + + faas_function_count_limit: int + """Functions count limit""" + + faas_namespace_count_limit: int + """Functions namespace count limit""" + + faas_ram_size_limit: int + """MB memory count for functions limit""" + + firewall_count_limit: int + """Firewalls Count limit""" + + floating_count_limit: int + """Floating IP Count limit""" + + gpu_count_limit: int + """GPU Count limit""" + + gpu_virtual_a100_count_limit: int + """Virtual A100 GPU card count limit""" + + gpu_virtual_h100_count_limit: int + """Virtual H100 GPU card count limit""" + + gpu_virtual_h200_count_limit: int + """Virtual H200 GPU card count limit""" + + gpu_virtual_l40s_count_limit: int + """Virtual L40S GPU card count limit""" + + image_count_limit: int + """Images Count limit""" + + image_size_limit: int + """Images Size, GiB limit""" + + ipu_count_limit: int + """IPU Count limit""" + + laas_topic_count_limit: int + """LaaS Topics Count limit""" + + loadbalancer_count_limit: int + """Load Balancers Count limit""" + + network_count_limit: int + """Networks Count limit""" + + ram_limit: int + """RAM Size, GiB limit""" + + region_id: int + """Region ID""" + + registry_count_limit: int + """Registries count limit""" + + registry_storage_limit: int + """Registries volume usage, GiB limit""" + + router_count_limit: int + """Routers Count limit""" + + secret_count_limit: int + """Secret Count limit""" + + servergroup_count_limit: int + """Placement Group Count limit""" + + sfs_count_limit: int + """Shared file system Count limit""" + + sfs_size_limit: int + """Shared file system Size, GiB limit""" + + shared_vm_count_limit: int + """Basic VMs Count limit""" + + snapshot_schedule_count_limit: int + """Snapshot Schedules Count limit""" + + subnet_count_limit: int + """Subnets Count limit""" + + vm_count_limit: int + """Instances Dedicated Count limit""" + + volume_count_limit: int + """Volumes Count limit""" + + volume_size_limit: int + """Volumes Size, GiB limit""" + + volume_snapshots_count_limit: int + """Snapshots Count limit""" + + volume_snapshots_size_limit: int + """Snapshots Size, GiB limit""" + + +class RequestedLimits(TypedDict, total=False): + """Limits you want to increase.""" + + global_limits: RequestedLimitsGlobalLimits + """Global entity quota limits""" + + regional_limits: Iterable[RequestedLimitsRegionalLimit] + """Regions and their quota limits""" diff --git a/src/gcore/types/cloud/quotas/request_get_response.py b/src/gcore/types/cloud/quotas/request_get_response.py new file mode 100644 index 00000000..9ca76084 --- /dev/null +++ b/src/gcore/types/cloud/quotas/request_get_response.py @@ -0,0 +1,229 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from ...._models import BaseModel + +__all__ = ["RequestGetResponse", "RequestedLimits", "RequestedLimitsGlobalLimits", "RequestedLimitsRegionalLimit"] + + +class RequestedLimitsGlobalLimits(BaseModel): + """Global entity quota limits""" + + inference_cpu_millicore_count_limit: Optional[int] = None + """Inference CPU millicore count limit""" + + inference_gpu_a100_count_limit: Optional[int] = None + """Inference GPU A100 Count limit""" + + inference_gpu_h100_count_limit: Optional[int] = None + """Inference GPU H100 Count limit""" + + inference_gpu_l40s_count_limit: Optional[int] = None + """Inference GPU L40s Count limit""" + + inference_instance_count_limit: Optional[int] = None + """Inference instance count limit""" + + keypair_count_limit: Optional[int] = None + """SSH Keys Count limit""" + + project_count_limit: Optional[int] = None + """Projects Count limit""" + + +class RequestedLimitsRegionalLimit(BaseModel): + baremetal_basic_count_limit: Optional[int] = None + """Basic bare metal servers count limit""" + + baremetal_gpu_a100_count_limit: Optional[int] = None + """Bare metal A100 GPU server count limit""" + + baremetal_gpu_count_limit: Optional[int] = None + """Total number of AI GPU bare metal servers. + + This field is deprecated and is now always calculated automatically as the sum + of `baremetal_gpu_a100_count_limit`, `baremetal_gpu_h100_count_limit`, + `baremetal_gpu_h200_count_limit`, and `baremetal_gpu_l40s_count_limit`. + """ + + baremetal_gpu_h100_count_limit: Optional[int] = None + """Bare metal H100 GPU server count limit""" + + baremetal_gpu_h200_count_limit: Optional[int] = None + """Bare metal H200 GPU server count limit""" + + baremetal_gpu_l40s_count_limit: Optional[int] = None + """Bare metal L40S GPU server count limit""" + + baremetal_hf_count_limit: Optional[int] = None + """High-frequency bare metal servers count limit""" + + baremetal_infrastructure_count_limit: Optional[int] = None + """Infrastructure bare metal servers count limit""" + + baremetal_network_count_limit: Optional[int] = None + """Bare metal Network Count limit""" + + baremetal_storage_count_limit: Optional[int] = None + """Storage bare metal servers count limit""" + + caas_container_count_limit: Optional[int] = None + """Containers count limit""" + + caas_cpu_count_limit: Optional[int] = None + """mCPU count for containers limit""" + + caas_gpu_count_limit: Optional[int] = None + """Containers gpu count limit""" + + caas_ram_size_limit: Optional[int] = None + """MB memory count for containers limit""" + + cluster_count_limit: Optional[int] = None + """K8s clusters count limit""" + + cpu_count_limit: Optional[int] = None + """vCPU Count limit""" + + dbaas_postgres_cluster_count_limit: Optional[int] = None + """DBaaS cluster count limit""" + + external_ip_count_limit: Optional[int] = None + """External IP Count limit""" + + faas_cpu_count_limit: Optional[int] = None + """mCPU count for functions limit""" + + faas_function_count_limit: Optional[int] = None + """Functions count limit""" + + faas_namespace_count_limit: Optional[int] = None + """Functions namespace count limit""" + + faas_ram_size_limit: Optional[int] = None + """MB memory count for functions limit""" + + firewall_count_limit: Optional[int] = None + """Firewalls Count limit""" + + floating_count_limit: Optional[int] = None + """Floating IP Count limit""" + + gpu_count_limit: Optional[int] = None + """GPU Count limit""" + + gpu_virtual_a100_count_limit: Optional[int] = None + """Virtual A100 GPU card count limit""" + + gpu_virtual_h100_count_limit: Optional[int] = None + """Virtual H100 GPU card count limit""" + + gpu_virtual_h200_count_limit: Optional[int] = None + """Virtual H200 GPU card count limit""" + + gpu_virtual_l40s_count_limit: Optional[int] = None + """Virtual L40S GPU card count limit""" + + image_count_limit: Optional[int] = None + """Images Count limit""" + + image_size_limit: Optional[int] = None + """Images Size, GiB limit""" + + ipu_count_limit: Optional[int] = None + """IPU Count limit""" + + laas_topic_count_limit: Optional[int] = None + """LaaS Topics Count limit""" + + loadbalancer_count_limit: Optional[int] = None + """Load Balancers Count limit""" + + network_count_limit: Optional[int] = None + """Networks Count limit""" + + ram_limit: Optional[int] = None + """RAM Size, GiB limit""" + + region_id: Optional[int] = None + """Region ID""" + + registry_count_limit: Optional[int] = None + """Registries count limit""" + + registry_storage_limit: Optional[int] = None + """Registries volume usage, GiB limit""" + + router_count_limit: Optional[int] = None + """Routers Count limit""" + + secret_count_limit: Optional[int] = None + """Secret Count limit""" + + servergroup_count_limit: Optional[int] = None + """Placement Group Count limit""" + + sfs_count_limit: Optional[int] = None + """Shared file system Count limit""" + + sfs_size_limit: Optional[int] = None + """Shared file system Size, GiB limit""" + + shared_vm_count_limit: Optional[int] = None + """Basic VMs Count limit""" + + snapshot_schedule_count_limit: Optional[int] = None + """Snapshot Schedules Count limit""" + + subnet_count_limit: Optional[int] = None + """Subnets Count limit""" + + vm_count_limit: Optional[int] = None + """Instances Dedicated Count limit""" + + volume_count_limit: Optional[int] = None + """Volumes Count limit""" + + volume_size_limit: Optional[int] = None + """Volumes Size, GiB limit""" + + volume_snapshots_count_limit: Optional[int] = None + """Snapshots Count limit""" + + volume_snapshots_size_limit: Optional[int] = None + """Snapshots Size, GiB limit""" + + +class RequestedLimits(BaseModel): + """Requested limits.""" + + global_limits: Optional[RequestedLimitsGlobalLimits] = None + """Global entity quota limits""" + + regional_limits: Optional[List[RequestedLimitsRegionalLimit]] = None + """Regions and their quota limits""" + + +class RequestGetResponse(BaseModel): + id: int + """Request ID""" + + client_id: int + """Client ID""" + + requested_limits: RequestedLimits + """Requested limits.""" + + status: str + """Request status""" + + created_at: Optional[datetime] = None + """Datetime when the request was created.""" + + description: Optional[str] = None + """Describe the reason, in general terms.""" + + updated_at: Optional[datetime] = None + """Datetime when the request was updated.""" diff --git a/src/gcore/types/cloud/quotas/request_list_params.py b/src/gcore/types/cloud/quotas/request_list_params.py new file mode 100644 index 00000000..56e39b19 --- /dev/null +++ b/src/gcore/types/cloud/quotas/request_list_params.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from datetime import datetime +from typing_extensions import Literal, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["RequestListParams"] + + +class RequestListParams(TypedDict, total=False): + created_from: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """Filter limit requests created at or after this datetime (inclusive)""" + + created_to: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """Filter limit requests created at or before this datetime (inclusive)""" + + limit: int + """Optional. Limit the number of returned items""" + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ + + request_ids: Iterable[int] + """List of limit request IDs for filtering""" + + status: List[Literal["done", "in progress", "rejected"]] + """List of limit requests statuses for filtering""" diff --git a/src/gcore/types/cloud/quotas/request_list_response.py b/src/gcore/types/cloud/quotas/request_list_response.py new file mode 100644 index 00000000..63cdce04 --- /dev/null +++ b/src/gcore/types/cloud/quotas/request_list_response.py @@ -0,0 +1,229 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from ...._models import BaseModel + +__all__ = ["RequestListResponse", "RequestedLimits", "RequestedLimitsGlobalLimits", "RequestedLimitsRegionalLimit"] + + +class RequestedLimitsGlobalLimits(BaseModel): + """Global entity quota limits""" + + inference_cpu_millicore_count_limit: Optional[int] = None + """Inference CPU millicore count limit""" + + inference_gpu_a100_count_limit: Optional[int] = None + """Inference GPU A100 Count limit""" + + inference_gpu_h100_count_limit: Optional[int] = None + """Inference GPU H100 Count limit""" + + inference_gpu_l40s_count_limit: Optional[int] = None + """Inference GPU L40s Count limit""" + + inference_instance_count_limit: Optional[int] = None + """Inference instance count limit""" + + keypair_count_limit: Optional[int] = None + """SSH Keys Count limit""" + + project_count_limit: Optional[int] = None + """Projects Count limit""" + + +class RequestedLimitsRegionalLimit(BaseModel): + baremetal_basic_count_limit: Optional[int] = None + """Basic bare metal servers count limit""" + + baremetal_gpu_a100_count_limit: Optional[int] = None + """Bare metal A100 GPU server count limit""" + + baremetal_gpu_count_limit: Optional[int] = None + """Total number of AI GPU bare metal servers. + + This field is deprecated and is now always calculated automatically as the sum + of `baremetal_gpu_a100_count_limit`, `baremetal_gpu_h100_count_limit`, + `baremetal_gpu_h200_count_limit`, and `baremetal_gpu_l40s_count_limit`. + """ + + baremetal_gpu_h100_count_limit: Optional[int] = None + """Bare metal H100 GPU server count limit""" + + baremetal_gpu_h200_count_limit: Optional[int] = None + """Bare metal H200 GPU server count limit""" + + baremetal_gpu_l40s_count_limit: Optional[int] = None + """Bare metal L40S GPU server count limit""" + + baremetal_hf_count_limit: Optional[int] = None + """High-frequency bare metal servers count limit""" + + baremetal_infrastructure_count_limit: Optional[int] = None + """Infrastructure bare metal servers count limit""" + + baremetal_network_count_limit: Optional[int] = None + """Bare metal Network Count limit""" + + baremetal_storage_count_limit: Optional[int] = None + """Storage bare metal servers count limit""" + + caas_container_count_limit: Optional[int] = None + """Containers count limit""" + + caas_cpu_count_limit: Optional[int] = None + """mCPU count for containers limit""" + + caas_gpu_count_limit: Optional[int] = None + """Containers gpu count limit""" + + caas_ram_size_limit: Optional[int] = None + """MB memory count for containers limit""" + + cluster_count_limit: Optional[int] = None + """K8s clusters count limit""" + + cpu_count_limit: Optional[int] = None + """vCPU Count limit""" + + dbaas_postgres_cluster_count_limit: Optional[int] = None + """DBaaS cluster count limit""" + + external_ip_count_limit: Optional[int] = None + """External IP Count limit""" + + faas_cpu_count_limit: Optional[int] = None + """mCPU count for functions limit""" + + faas_function_count_limit: Optional[int] = None + """Functions count limit""" + + faas_namespace_count_limit: Optional[int] = None + """Functions namespace count limit""" + + faas_ram_size_limit: Optional[int] = None + """MB memory count for functions limit""" + + firewall_count_limit: Optional[int] = None + """Firewalls Count limit""" + + floating_count_limit: Optional[int] = None + """Floating IP Count limit""" + + gpu_count_limit: Optional[int] = None + """GPU Count limit""" + + gpu_virtual_a100_count_limit: Optional[int] = None + """Virtual A100 GPU card count limit""" + + gpu_virtual_h100_count_limit: Optional[int] = None + """Virtual H100 GPU card count limit""" + + gpu_virtual_h200_count_limit: Optional[int] = None + """Virtual H200 GPU card count limit""" + + gpu_virtual_l40s_count_limit: Optional[int] = None + """Virtual L40S GPU card count limit""" + + image_count_limit: Optional[int] = None + """Images Count limit""" + + image_size_limit: Optional[int] = None + """Images Size, GiB limit""" + + ipu_count_limit: Optional[int] = None + """IPU Count limit""" + + laas_topic_count_limit: Optional[int] = None + """LaaS Topics Count limit""" + + loadbalancer_count_limit: Optional[int] = None + """Load Balancers Count limit""" + + network_count_limit: Optional[int] = None + """Networks Count limit""" + + ram_limit: Optional[int] = None + """RAM Size, GiB limit""" + + region_id: Optional[int] = None + """Region ID""" + + registry_count_limit: Optional[int] = None + """Registries count limit""" + + registry_storage_limit: Optional[int] = None + """Registries volume usage, GiB limit""" + + router_count_limit: Optional[int] = None + """Routers Count limit""" + + secret_count_limit: Optional[int] = None + """Secret Count limit""" + + servergroup_count_limit: Optional[int] = None + """Placement Group Count limit""" + + sfs_count_limit: Optional[int] = None + """Shared file system Count limit""" + + sfs_size_limit: Optional[int] = None + """Shared file system Size, GiB limit""" + + shared_vm_count_limit: Optional[int] = None + """Basic VMs Count limit""" + + snapshot_schedule_count_limit: Optional[int] = None + """Snapshot Schedules Count limit""" + + subnet_count_limit: Optional[int] = None + """Subnets Count limit""" + + vm_count_limit: Optional[int] = None + """Instances Dedicated Count limit""" + + volume_count_limit: Optional[int] = None + """Volumes Count limit""" + + volume_size_limit: Optional[int] = None + """Volumes Size, GiB limit""" + + volume_snapshots_count_limit: Optional[int] = None + """Snapshots Count limit""" + + volume_snapshots_size_limit: Optional[int] = None + """Snapshots Size, GiB limit""" + + +class RequestedLimits(BaseModel): + """Requested limits.""" + + global_limits: Optional[RequestedLimitsGlobalLimits] = None + """Global entity quota limits""" + + regional_limits: Optional[List[RequestedLimitsRegionalLimit]] = None + """Regions and their quota limits""" + + +class RequestListResponse(BaseModel): + id: int + """Request ID""" + + client_id: int + """Client ID""" + + requested_limits: RequestedLimits + """Requested limits.""" + + status: str + """Request status""" + + created_at: Optional[datetime] = None + """Datetime when the request was created.""" + + description: Optional[str] = None + """Describe the reason, in general terms.""" + + updated_at: Optional[datetime] = None + """Datetime when the request was updated.""" diff --git a/src/gcore/types/cloud/region.py b/src/gcore/types/cloud/region.py new file mode 100644 index 00000000..b2bf4ac8 --- /dev/null +++ b/src/gcore/types/cloud/region.py @@ -0,0 +1,103 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["Region", "Coordinates"] + + +class Coordinates(BaseModel): + """Coordinates of the region""" + + latitude: Union[float, str] + + longitude: Union[float, str] + + +class Region(BaseModel): + id: int + """Region ID""" + + access_level: Literal["core", "edge"] + """The access level of the region.""" + + available_volume_types: Optional[List[str]] = None + """List of available volume types, 'standard', 'ssd_hiiops', 'cold'].""" + + coordinates: Optional[Coordinates] = None + """Coordinates of the region""" + + country: str + """Two-letter country code, ISO 3166-1 alpha-2""" + + created_at: datetime + """Region creation date and time""" + + created_on: datetime + """This field is deprecated. Use `created_at` instead.""" + + display_name: str + """Human-readable region name""" + + endpoint_type: Literal["admin", "internal", "public"] + """Endpoint type""" + + external_network_id: Optional[str] = None + """External network ID for Neutron""" + + file_share_types: Optional[List[Literal["standard", "vast"]]] = None + """List of available file share types""" + + has_ai: bool + """Region has AI capability""" + + has_ai_gpu: bool + """Region has AI GPU capability""" + + has_baremetal: bool + """Region has bare metal capability""" + + has_basic_vm: bool + """Region has basic vm capability""" + + has_dbaas: bool + """Region has DBAAS service""" + + has_ddos: bool + """Region has Advanced DDoS Protection capability""" + + has_k8s: bool + """Region has managed kubernetes capability""" + + has_kvm: bool + """Region has KVM virtualization capability""" + + has_sfs: bool + """Region has SFS capability""" + + keystone_id: int + """Foreign key to Keystone entity""" + + keystone_name: str + """Technical region name""" + + metrics_database_id: Optional[int] = None + """Foreign key to Metrics database entity""" + + state: Literal["ACTIVE", "DELETED", "DELETING", "DELETION_FAILED", "INACTIVE", "MAINTENANCE", "NEW"] + """Region state""" + + task_id: Optional[str] = None + """This field is deprecated and can be ignored""" + + vlan_physical_network: str + """Physical network name to create vlan networks""" + + zone: Optional[Literal["AMERICAS", "APAC", "EMEA", "RUSSIA_AND_CIS"]] = None + """Geographical zone""" + + ddos_endpoint_id: Optional[int] = None + """DDoS endpoint ID""" diff --git a/src/gcore/types/cloud/region_get_params.py b/src/gcore/types/cloud/region_get_params.py new file mode 100644 index 00000000..5d667ede --- /dev/null +++ b/src/gcore/types/cloud/region_get_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["RegionGetParams"] + + +class RegionGetParams(TypedDict, total=False): + region_id: int + """Region ID""" + + show_volume_types: bool + """ + If true, null `available_volume_type` is replaced with a list of available + volume types. + """ diff --git a/src/gcore/types/cloud/region_list_params.py b/src/gcore/types/cloud/region_list_params.py new file mode 100644 index 00000000..ac7b106b --- /dev/null +++ b/src/gcore/types/cloud/region_list_params.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["RegionListParams"] + + +class RegionListParams(TypedDict, total=False): + limit: int + """Limit the number of returned regions. + + Falls back to default of 100 if not specified. Limited by max limit value of + 1000 + """ + + offset: int + """Offset value is used to exclude the first set of records from the result""" + + order_by: Literal["created_at.asc", "created_at.desc", "display_name.asc", "display_name.desc"] + """Order by field and direction.""" + + product: Literal["containers", "inference"] + """If defined then return only regions that support given product.""" + + show_volume_types: bool + """ + If true, null `available_volume_type` is replaced with a list of available + volume types. + """ diff --git a/src/gcore/types/cloud/registries/__init__.py b/src/gcore/types/cloud/registries/__init__.py new file mode 100644 index 00000000..a4e5934f --- /dev/null +++ b/src/gcore/types/cloud/registries/__init__.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .registry_user import RegistryUser as RegistryUser +from .registry_artifact import RegistryArtifact as RegistryArtifact +from .registry_user_list import RegistryUserList as RegistryUserList +from .user_create_params import UserCreateParams as UserCreateParams +from .user_update_params import UserUpdateParams as UserUpdateParams +from .registry_repository import RegistryRepository as RegistryRepository +from .registry_user_created import RegistryUserCreated as RegistryUserCreated +from .registry_artifact_list import RegistryArtifactList as RegistryArtifactList +from .registry_repository_list import RegistryRepositoryList as RegistryRepositoryList +from .user_create_multiple_params import UserCreateMultipleParams as UserCreateMultipleParams +from .user_refresh_secret_response import UserRefreshSecretResponse as UserRefreshSecretResponse diff --git a/src/gcore/types/cloud/registries/registry_artifact.py b/src/gcore/types/cloud/registries/registry_artifact.py new file mode 100644 index 00000000..326adeb6 --- /dev/null +++ b/src/gcore/types/cloud/registries/registry_artifact.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from datetime import datetime + +from ...._models import BaseModel +from ..registry_tag import RegistryTag + +__all__ = ["RegistryArtifact"] + + +class RegistryArtifact(BaseModel): + id: int + """Repository ID""" + + digest: str + """Artifact digest""" + + pulled_at: datetime + """Artifact last pull date-time""" + + pushed_at: datetime + """Artifact push date-time""" + + registry_id: int + """Artifact registry ID""" + + repository_id: int + """Artifact repository ID""" + + size: int + """Artifact size, bytes""" + + tags: List[RegistryTag] + """Artifact tags""" diff --git a/src/gcore/types/cloud/registries/registry_artifact_list.py b/src/gcore/types/cloud/registries/registry_artifact_list.py new file mode 100644 index 00000000..4d0e3959 --- /dev/null +++ b/src/gcore/types/cloud/registries/registry_artifact_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ...._models import BaseModel +from .registry_artifact import RegistryArtifact + +__all__ = ["RegistryArtifactList"] + + +class RegistryArtifactList(BaseModel): + count: int + """Number of objects""" + + results: List[RegistryArtifact] + """Objects""" diff --git a/src/gcore/types/cloud/registries/registry_repository.py b/src/gcore/types/cloud/registries/registry_repository.py new file mode 100644 index 00000000..9d1ddba5 --- /dev/null +++ b/src/gcore/types/cloud/registries/registry_repository.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ...._models import BaseModel + +__all__ = ["RegistryRepository"] + + +class RegistryRepository(BaseModel): + id: int + """Repository ID""" + + artifact_count: int + """Number of artifacts in the repository""" + + created_at: datetime + """Repository creation date-time""" + + name: str + """Repository name""" + + pull_count: int + """Number of pools from the repository""" + + registry_id: int + """Repository registry ID""" + + updated_at: datetime + """Repository modification date-time""" diff --git a/src/gcore/types/cloud/registries/registry_repository_list.py b/src/gcore/types/cloud/registries/registry_repository_list.py new file mode 100644 index 00000000..2ef46cf2 --- /dev/null +++ b/src/gcore/types/cloud/registries/registry_repository_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ...._models import BaseModel +from .registry_repository import RegistryRepository + +__all__ = ["RegistryRepositoryList"] + + +class RegistryRepositoryList(BaseModel): + count: int + """Number of objects""" + + results: List[RegistryRepository] + """Objects""" diff --git a/src/gcore/types/cloud/registries/registry_user.py b/src/gcore/types/cloud/registries/registry_user.py new file mode 100644 index 00000000..23de4c01 --- /dev/null +++ b/src/gcore/types/cloud/registries/registry_user.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ...._models import BaseModel + +__all__ = ["RegistryUser"] + + +class RegistryUser(BaseModel): + id: int + """User ID""" + + created_at: datetime + """User creation date-time""" + + duration: int + """User account operating time, days""" + + expires_at: datetime + """User operation end date-time""" + + name: str + """User name""" + + read_only: bool + """Read-only user""" diff --git a/src/gcore/types/cloud/registries/registry_user_created.py b/src/gcore/types/cloud/registries/registry_user_created.py new file mode 100644 index 00000000..42564a72 --- /dev/null +++ b/src/gcore/types/cloud/registries/registry_user_created.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ...._models import BaseModel + +__all__ = ["RegistryUserCreated"] + + +class RegistryUserCreated(BaseModel): + id: int + """User ID""" + + created_at: datetime + """User creation date-time""" + + duration: int + """User account operating time, days""" + + expires_at: datetime + """User operation end date-time""" + + name: str + """User name""" + + read_only: bool + """Read-only user""" + + secret: str + """User secret""" diff --git a/src/gcore/types/cloud/registries/registry_user_list.py b/src/gcore/types/cloud/registries/registry_user_list.py new file mode 100644 index 00000000..980254a8 --- /dev/null +++ b/src/gcore/types/cloud/registries/registry_user_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ...._models import BaseModel +from .registry_user import RegistryUser + +__all__ = ["RegistryUserList"] + + +class RegistryUserList(BaseModel): + count: int + """Number of objects""" + + results: List[RegistryUser] + """Objects""" diff --git a/src/gcore/types/cloud/registries/user_create_multiple_params.py b/src/gcore/types/cloud/registries/user_create_multiple_params.py new file mode 100644 index 00000000..e580e8dc --- /dev/null +++ b/src/gcore/types/cloud/registries/user_create_multiple_params.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["UserCreateMultipleParams", "User"] + + +class UserCreateMultipleParams(TypedDict, total=False): + project_id: int + + region_id: int + + users: Required[Iterable[User]] + """Set of users""" + + +class User(TypedDict, total=False): + duration: Required[int] + """User account operating time, days""" + + name: Required[str] + """A name for the registry user. + + Should be in lowercase, consisting only of numbers and letters, + + with maximum length of 16 characters + """ + + read_only: bool + """Read-only user""" + + secret: str + """User secret""" diff --git a/src/gcore/types/cloud/registries/user_create_params.py b/src/gcore/types/cloud/registries/user_create_params.py new file mode 100644 index 00000000..a658b14c --- /dev/null +++ b/src/gcore/types/cloud/registries/user_create_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["UserCreateParams"] + + +class UserCreateParams(TypedDict, total=False): + project_id: int + + region_id: int + + duration: Required[int] + """User account operating time, days""" + + name: Required[str] + """A name for the registry user. + + Should be in lowercase, consisting only of numbers and letters, + + with maximum length of 16 characters + """ + + read_only: bool + """Read-only user""" + + secret: str + """User secret""" diff --git a/src/gcore/types/cloud/registries/user_refresh_secret_response.py b/src/gcore/types/cloud/registries/user_refresh_secret_response.py new file mode 100644 index 00000000..255c1e8a --- /dev/null +++ b/src/gcore/types/cloud/registries/user_refresh_secret_response.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ...._models import BaseModel + +__all__ = ["UserRefreshSecretResponse"] + + +class UserRefreshSecretResponse(BaseModel): + id: int + """User ID""" + + created_at: datetime + """User creation date-time""" + + duration: int + """User account operating time, days""" + + expires_at: datetime + """User operation end date-time""" + + name: str + """User name""" + + read_only: bool + """Read-only user""" + + secret: str + """User secret""" diff --git a/src/gcore/types/cloud/registries/user_update_params.py b/src/gcore/types/cloud/registries/user_update_params.py new file mode 100644 index 00000000..a4be7b07 --- /dev/null +++ b/src/gcore/types/cloud/registries/user_update_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["UserUpdateParams"] + + +class UserUpdateParams(TypedDict, total=False): + project_id: int + + region_id: int + + registry_id: Required[int] + + duration: Required[int] + """User account operating time, days""" + + read_only: bool + """Read-only user""" diff --git a/src/gcore/types/cloud/registry.py b/src/gcore/types/cloud/registry.py new file mode 100644 index 00000000..96f588c4 --- /dev/null +++ b/src/gcore/types/cloud/registry.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["Registry"] + + +class Registry(BaseModel): + id: int + """Registry ID""" + + created_at: datetime + """Registry creation date-time""" + + name: str + """Registry name""" + + repo_count: int + """Number of repositories in the registry""" + + storage_limit: int + """Registry storage limit, GiB""" + + storage_used: int + """Registry storage used, bytes""" + + updated_at: datetime + """Registry modification date-time""" + + url: str + """Registry url""" diff --git a/src/gcore/types/cloud/registry_create_params.py b/src/gcore/types/cloud/registry_create_params.py new file mode 100644 index 00000000..2d5ecfbb --- /dev/null +++ b/src/gcore/types/cloud/registry_create_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RegistryCreateParams"] + + +class RegistryCreateParams(TypedDict, total=False): + project_id: int + + region_id: int + + name: Required[str] + """A name for the container registry. + + Should be in lowercase, consisting only of numbers, letters and -, + + with maximum length of 24 characters + """ + + storage_limit: int + """Registry storage limit, GiB""" diff --git a/src/gcore/types/cloud/registry_list.py b/src/gcore/types/cloud/registry_list.py new file mode 100644 index 00000000..1f31d5fb --- /dev/null +++ b/src/gcore/types/cloud/registry_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from .registry import Registry +from ..._models import BaseModel + +__all__ = ["RegistryList"] + + +class RegistryList(BaseModel): + count: int + """Number of objects""" + + results: List[Registry] + """Objects""" diff --git a/src/gcore/types/cloud/registry_resize_params.py b/src/gcore/types/cloud/registry_resize_params.py new file mode 100644 index 00000000..fb313913 --- /dev/null +++ b/src/gcore/types/cloud/registry_resize_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["RegistryResizeParams"] + + +class RegistryResizeParams(TypedDict, total=False): + project_id: int + + region_id: int + + storage_limit: int + """Registry storage limit, GiB""" diff --git a/src/gcore/types/cloud/registry_tag.py b/src/gcore/types/cloud/registry_tag.py new file mode 100644 index 00000000..e0668385 --- /dev/null +++ b/src/gcore/types/cloud/registry_tag.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["RegistryTag"] + + +class RegistryTag(BaseModel): + id: int + """Tag ID""" + + artifact_id: int + """Artifact ID""" + + name: str + """Tag name""" + + pulled_at: datetime + """Tag last pull date-time""" + + pushed_at: datetime + """Tag push date-time""" + + repository_id: int + """Repository ID""" diff --git a/src/gcore/types/cloud/reserved_fixed_ip.py b/src/gcore/types/cloud/reserved_fixed_ip.py new file mode 100644 index 00000000..f059bed8 --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ip.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from .network import Network +from ..._models import BaseModel +from .allowed_address_pairs import AllowedAddressPairs + +__all__ = ["ReservedFixedIP", "Attachment", "Reservation"] + + +class Attachment(BaseModel): + resource_id: Optional[str] = None + """Resource ID""" + + resource_type: Optional[str] = None + """Resource type""" + + +class Reservation(BaseModel): + """Reserved fixed IP status with resource type and ID it is attached to""" + + resource_id: Optional[str] = None + """ID of the instance or load balancer the IP is attached to""" + + resource_type: Optional[str] = None + """Resource type of the resource the IP is attached to""" + + status: Optional[str] = None + """IP reservation status""" + + +class ReservedFixedIP(BaseModel): + allowed_address_pairs: List[AllowedAddressPairs] + """Group of subnet masks and/or IP addresses that share the current IP as VIP""" + + attachments: List[Attachment] + """Reserved fixed IP attachment entities""" + + created_at: datetime + """Datetime when the reserved fixed IP was created""" + + is_external: bool + """If reserved fixed IP belongs to a public network""" + + is_vip: bool + """If reserved fixed IP is a VIP""" + + name: str + """Reserved fixed IP name""" + + network: Network + """Network details""" + + network_id: str + """ID of the network the port is attached to""" + + port_id: str + """ID of the port underlying the reserved fixed IP""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + reservation: Reservation + """Reserved fixed IP status with resource type and ID it is attached to""" + + status: str + """Underlying port status""" + + updated_at: datetime + """Datetime when the reserved fixed IP was last updated""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + fixed_ip_address: Optional[str] = None + """IPv4 address of the reserved fixed IP""" + + fixed_ipv6_address: Optional[str] = None + """IPv6 address of the reserved fixed IP""" + + project_id: Optional[int] = None + """Project ID""" + + subnet_id: Optional[str] = None + """ID of the subnet that owns the IP address""" + + subnet_v6_id: Optional[str] = None + """ID of the subnet that owns the IPv6 address""" + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ diff --git a/src/gcore/types/cloud/reserved_fixed_ip_create_params.py b/src/gcore/types/cloud/reserved_fixed_ip_create_params.py new file mode 100644 index 00000000..553101d5 --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ip_create_params.py @@ -0,0 +1,107 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .interface_ip_family import InterfaceIPFamily + +__all__ = [ + "ReservedFixedIPCreateParams", + "NewReservedFixedIPExternalSerializer", + "NewReservedFixedIPSpecificSubnetSerializer", + "NewReservedFixedIPAnySubnetSerializer", + "NewReservedFixedIPSpecificIPAddressSerializer", + "NewReservedFixedIPSpecificPortSerializer", +] + + +class NewReservedFixedIPExternalSerializer(TypedDict, total=False): + project_id: int + + region_id: int + + type: Required[Literal["external"]] + """Must be 'external'""" + + ip_family: Optional[InterfaceIPFamily] + """Which subnets should be selected: IPv4, IPv6 or use dual stack.""" + + is_vip: bool + """If reserved fixed IP is a VIP""" + + +class NewReservedFixedIPSpecificSubnetSerializer(TypedDict, total=False): + project_id: int + + region_id: int + + subnet_id: Required[str] + """Reserved fixed IP will be allocated in this subnet""" + + type: Required[Literal["subnet"]] + """Must be 'subnet'.""" + + is_vip: bool + """If reserved fixed IP is a VIP""" + + +class NewReservedFixedIPAnySubnetSerializer(TypedDict, total=False): + project_id: int + + region_id: int + + network_id: Required[str] + """Reserved fixed IP will be allocated in a subnet of this network""" + + type: Required[Literal["any_subnet"]] + """Must be 'any_subnet'.""" + + ip_family: Optional[InterfaceIPFamily] + """Which subnets should be selected: IPv4, IPv6 or use dual stack.""" + + is_vip: bool + """If reserved fixed IP is a VIP""" + + +class NewReservedFixedIPSpecificIPAddressSerializer(TypedDict, total=False): + project_id: int + + region_id: int + + ip_address: Required[str] + """Reserved fixed IP will be allocated the given IP address""" + + network_id: Required[str] + """Reserved fixed IP will be allocated in a subnet of this network""" + + type: Required[Literal["ip_address"]] + """Must be 'ip_address'.""" + + is_vip: bool + """If reserved fixed IP is a VIP""" + + +class NewReservedFixedIPSpecificPortSerializer(TypedDict, total=False): + project_id: int + + region_id: int + + port_id: Required[str] + """ + Port ID to make a reserved fixed IP (for example, `vip_port_id` of the Load + Balancer entity). + """ + + type: Required[Literal["port"]] + """Must be 'port'.""" + + +ReservedFixedIPCreateParams: TypeAlias = Union[ + NewReservedFixedIPExternalSerializer, + NewReservedFixedIPSpecificSubnetSerializer, + NewReservedFixedIPAnySubnetSerializer, + NewReservedFixedIPSpecificIPAddressSerializer, + NewReservedFixedIPSpecificPortSerializer, +] diff --git a/src/gcore/types/cloud/reserved_fixed_ip_list_params.py b/src/gcore/types/cloud/reserved_fixed_ip_list_params.py new file mode 100644 index 00000000..4678f7c5 --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ip_list_params.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ReservedFixedIPListParams"] + + +class ReservedFixedIPListParams(TypedDict, total=False): + project_id: int + + region_id: int + + available_only: bool + """ + Set to true if the response should only list IP addresses that are not attached + to any instance + """ + + device_id: str + """Filter IPs by device ID it is attached to""" + + external_only: bool + """Set to true if the response should only list public IP addresses""" + + internal_only: bool + """Set to true if the response should only list private IP addresses""" + + ip_address: str + """An IPv4 address to filter results by. Regular expression allowed""" + + limit: int + """Limit the number of returned IPs""" + + offset: int + """Offset value is used to exclude the first set of records from the result""" + + order_by: str + """ + Ordering reserved fixed IP list result by name, status, `updated_at`, + `created_at` or `fixed_ip_address` fields and directions (status.asc), default + is "fixed_ip_address.asc" + """ + + vip_only: bool + """Set to true if the response should only list VIPs""" diff --git a/src/gcore/types/cloud/reserved_fixed_ip_update_params.py b/src/gcore/types/cloud/reserved_fixed_ip_update_params.py new file mode 100644 index 00000000..9d2bbb2d --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ip_update_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ReservedFixedIPUpdateParams"] + + +class ReservedFixedIPUpdateParams(TypedDict, total=False): + project_id: int + + region_id: int + + is_vip: Required[bool] + """If reserved fixed IP should be a VIP""" diff --git a/src/gcore/types/cloud/reserved_fixed_ips/__init__.py b/src/gcore/types/cloud/reserved_fixed_ips/__init__.py new file mode 100644 index 00000000..a796bf7c --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ips/__init__.py @@ -0,0 +1,6 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .ip_with_subnet import IPWithSubnet as IPWithSubnet +from .vip_toggle_params import VipToggleParams as VipToggleParams diff --git a/src/gcore/types/cloud/reserved_fixed_ips/ip_with_subnet.py b/src/gcore/types/cloud/reserved_fixed_ips/ip_with_subnet.py new file mode 100644 index 00000000..b835f64b --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ips/ip_with_subnet.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..subnet import Subnet +from ...._models import BaseModel + +__all__ = ["IPWithSubnet"] + + +class IPWithSubnet(BaseModel): + ip_address: str + """IP address""" + + subnet: Subnet + """Subnet details""" + + subnet_id: str + """ID of the subnet that allocated the IP""" diff --git a/src/gcore/types/cloud/reserved_fixed_ips/vip/__init__.py b/src/gcore/types/cloud/reserved_fixed_ips/vip/__init__.py new file mode 100644 index 00000000..0dd4eb7e --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ips/vip/__init__.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .candidate_port import CandidatePort as CandidatePort +from .connected_port import ConnectedPort as ConnectedPort +from .candidate_port_list import CandidatePortList as CandidatePortList +from .connected_port_list import ConnectedPortList as ConnectedPortList +from .connected_port_add_params import ConnectedPortAddParams as ConnectedPortAddParams +from .connected_port_replace_params import ConnectedPortReplaceParams as ConnectedPortReplaceParams diff --git a/src/gcore/types/cloud/reserved_fixed_ips/vip/candidate_port.py b/src/gcore/types/cloud/reserved_fixed_ips/vip/candidate_port.py new file mode 100644 index 00000000..4799c337 --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ips/vip/candidate_port.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ...network import Network +from ....._models import BaseModel +from ..ip_with_subnet import IPWithSubnet + +__all__ = ["CandidatePort"] + + +class CandidatePort(BaseModel): + instance_id: str + """ID of the instance that owns the port""" + + instance_name: str + """Name of the instance that owns the port""" + + ip_assignments: List[IPWithSubnet] + """IP addresses assigned to this port""" + + network: Network + """Network details""" + + port_id: str + """Port ID that shares VIP""" diff --git a/src/gcore/types/cloud/reserved_fixed_ips/vip/candidate_port_list.py b/src/gcore/types/cloud/reserved_fixed_ips/vip/candidate_port_list.py new file mode 100644 index 00000000..3c68db42 --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ips/vip/candidate_port_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ....._models import BaseModel +from .candidate_port import CandidatePort + +__all__ = ["CandidatePortList"] + + +class CandidatePortList(BaseModel): + count: int + """Number of objects""" + + results: List[CandidatePort] + """Objects""" diff --git a/src/gcore/types/cloud/reserved_fixed_ips/vip/connected_port.py b/src/gcore/types/cloud/reserved_fixed_ips/vip/connected_port.py new file mode 100644 index 00000000..b368f281 --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ips/vip/connected_port.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ...network import Network +from ....._models import BaseModel +from ..ip_with_subnet import IPWithSubnet + +__all__ = ["ConnectedPort"] + + +class ConnectedPort(BaseModel): + instance_id: str + """ID of the instance that owns the port""" + + instance_name: str + """Name of the instance that owns the port""" + + ip_assignments: List[IPWithSubnet] + """IP addresses assigned to this port""" + + network: Network + """Network details""" + + port_id: str + """Port ID that shares VIP""" diff --git a/src/gcore/types/cloud/reserved_fixed_ips/vip/connected_port_add_params.py b/src/gcore/types/cloud/reserved_fixed_ips/vip/connected_port_add_params.py new file mode 100644 index 00000000..be2667e3 --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ips/vip/connected_port_add_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from ....._types import SequenceNotStr + +__all__ = ["ConnectedPortAddParams"] + + +class ConnectedPortAddParams(TypedDict, total=False): + project_id: int + + region_id: int + + port_ids: SequenceNotStr[str] + """List of port IDs that will share one VIP""" diff --git a/src/gcore/types/cloud/reserved_fixed_ips/vip/connected_port_list.py b/src/gcore/types/cloud/reserved_fixed_ips/vip/connected_port_list.py new file mode 100644 index 00000000..6a0a2251 --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ips/vip/connected_port_list.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ....._models import BaseModel +from .connected_port import ConnectedPort + +__all__ = ["ConnectedPortList"] + + +class ConnectedPortList(BaseModel): + count: int + """Number of objects""" + + results: List[ConnectedPort] + """Objects""" diff --git a/src/gcore/types/cloud/reserved_fixed_ips/vip/connected_port_replace_params.py b/src/gcore/types/cloud/reserved_fixed_ips/vip/connected_port_replace_params.py new file mode 100644 index 00000000..860428e7 --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ips/vip/connected_port_replace_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from ....._types import SequenceNotStr + +__all__ = ["ConnectedPortReplaceParams"] + + +class ConnectedPortReplaceParams(TypedDict, total=False): + project_id: int + + region_id: int + + port_ids: SequenceNotStr[str] + """List of port IDs that will share one VIP""" diff --git a/src/gcore/types/cloud/reserved_fixed_ips/vip_toggle_params.py b/src/gcore/types/cloud/reserved_fixed_ips/vip_toggle_params.py new file mode 100644 index 00000000..9963340d --- /dev/null +++ b/src/gcore/types/cloud/reserved_fixed_ips/vip_toggle_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["VipToggleParams"] + + +class VipToggleParams(TypedDict, total=False): + project_id: int + + region_id: int + + is_vip: Required[bool] + """If reserved fixed IP should be a VIP""" diff --git a/src/gcore/types/cloud/route.py b/src/gcore/types/cloud/route.py new file mode 100644 index 00000000..f9854287 --- /dev/null +++ b/src/gcore/types/cloud/route.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["Route"] + + +class Route(BaseModel): + destination: str + """CIDR of destination IPv4 subnet.""" + + nexthop: str + """ + IPv4 address to forward traffic to if it's destination IP matches 'destination' + CIDR. + """ diff --git a/src/gcore/types/cloud/secret.py b/src/gcore/types/cloud/secret.py new file mode 100644 index 00000000..e7eb5015 --- /dev/null +++ b/src/gcore/types/cloud/secret.py @@ -0,0 +1,64 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["Secret"] + + +class Secret(BaseModel): + id: str + """Secret uuid""" + + name: str + """Secret name""" + + secret_type: Literal["certificate", "opaque", "passphrase", "private", "public", "symmetric"] + """Secret type, base64 encoded. + + symmetric - Used for storing byte arrays such as keys suitable for symmetric + encryption; public - Used for storing the public key of an asymmetric keypair; + private - Used for storing the private key of an asymmetric keypair; + passphrase - Used for storing plain text passphrases; certificate - Used for + storing cryptographic certificates such as X.509 certificates; opaque - Used for + backwards compatibility with previous versions of the API + """ + + status: str + """Status""" + + algorithm: Optional[str] = None + """Metadata provided by a user or system for informational purposes. + + Defaults to None + """ + + bit_length: Optional[int] = None + """Metadata provided by a user or system for informational purposes. + + Value must be greater than zero. Defaults to None + """ + + content_types: Optional[Dict[str, str]] = None + """Describes the content-types that can be used to retrieve the payload. + + The content-type used with symmetric secrets is application/octet-stream + """ + + created: Optional[datetime] = None + """Datetime when the secret was created. The format is 2020-01-01T12:00:00+00:00""" + + expiration: Optional[datetime] = None + """Datetime when the secret will expire. + + The format is 2020-01-01T12:00:00+00:00. Defaults to None + """ + + mode: Optional[str] = None + """Metadata provided by a user or system for informational purposes. + + Defaults to None + """ diff --git a/src/gcore/types/cloud/secret_list_params.py b/src/gcore/types/cloud/secret_list_params.py new file mode 100644 index 00000000..694229eb --- /dev/null +++ b/src/gcore/types/cloud/secret_list_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["SecretListParams"] + + +class SecretListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + limit: int + """Optional. Limit the number of returned items""" + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ diff --git a/src/gcore/types/cloud/secret_upload_tls_certificate_params.py b/src/gcore/types/cloud/secret_upload_tls_certificate_params.py new file mode 100644 index 00000000..524b58ad --- /dev/null +++ b/src/gcore/types/cloud/secret_upload_tls_certificate_params.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["SecretUploadTlsCertificateParams", "Payload"] + + +class SecretUploadTlsCertificateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: Required[str] + """Secret name""" + + payload: Required[Payload] + """Secret payload.""" + + expiration: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """Datetime when the secret will expire. Defaults to None""" + + +class Payload(TypedDict, total=False): + """Secret payload.""" + + certificate: Required[str] + """SSL certificate in PEM format.""" + + certificate_chain: Required[str] + """SSL certificate chain of intermediates and root certificates in PEM format.""" + + private_key: Required[str] + """SSL private key in PEM format.""" diff --git a/src/gcore/types/cloud/security_group.py b/src/gcore/types/cloud/security_group.py new file mode 100644 index 00000000..412b43d5 --- /dev/null +++ b/src/gcore/types/cloud/security_group.py @@ -0,0 +1,52 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from .tag import Tag +from ..._models import BaseModel +from .security_group_rule import SecurityGroupRule + +__all__ = ["SecurityGroup"] + + +class SecurityGroup(BaseModel): + id: str + """Security group ID""" + + created_at: datetime + """Datetime when the security group was created""" + + name: str + """Security group name""" + + project_id: int + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + revision_number: int + """The number of revisions""" + + tags_v2: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + updated_at: datetime + """Datetime when the security group was last updated""" + + description: Optional[str] = None + """Security group description""" + + security_group_rules: Optional[List[SecurityGroupRule]] = None + """Security group rules""" diff --git a/src/gcore/types/cloud/security_group_copy_params.py b/src/gcore/types/cloud/security_group_copy_params.py new file mode 100644 index 00000000..c93aa980 --- /dev/null +++ b/src/gcore/types/cloud/security_group_copy_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["SecurityGroupCopyParams"] + + +class SecurityGroupCopyParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: Required[str] + """Name.""" diff --git a/src/gcore/types/cloud/security_group_create_params.py b/src/gcore/types/cloud/security_group_create_params.py new file mode 100644 index 00000000..d4904c5d --- /dev/null +++ b/src/gcore/types/cloud/security_group_create_params.py @@ -0,0 +1,88 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["SecurityGroupCreateParams", "Rule"] + + +class SecurityGroupCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: Required[str] + """Security group name""" + + description: str + """Security group description""" + + rules: Iterable[Rule] + """Security group rules""" + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + +class Rule(TypedDict, total=False): + direction: Required[Literal["egress", "ingress"]] + """ + Ingress or egress, which is the direction in which the security group is applied + """ + + description: str + """Rule description""" + + ethertype: Literal["IPv4", "IPv6"] + """Ether type""" + + port_range_max: Optional[int] + """The maximum port number in the range that is matched by the security group rule""" + + port_range_min: Optional[int] + """The minimum port number in the range that is matched by the security group rule""" + + protocol: Literal[ + "ah", + "any", + "dccp", + "egp", + "esp", + "gre", + "icmp", + "igmp", + "ipencap", + "ipip", + "ipv6-encap", + "ipv6-frag", + "ipv6-icmp", + "ipv6-nonxt", + "ipv6-opts", + "ipv6-route", + "ospf", + "pgm", + "rsvp", + "sctp", + "tcp", + "udp", + "udplite", + "vrrp", + ] + """Protocol""" + + remote_group_id: str + """The remote group UUID to associate with this security group""" + + remote_ip_prefix: Optional[str] + """The remote IP prefix that is matched by this security group rule""" diff --git a/src/gcore/types/cloud/security_group_list_params.py b/src/gcore/types/cloud/security_group_list_params.py new file mode 100644 index 00000000..0f13ddad --- /dev/null +++ b/src/gcore/types/cloud/security_group_list_params.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["SecurityGroupListParams"] + + +class SecurityGroupListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + limit: int + """Limit of items on a single page""" + + name: str + """Optional. Filter by name. Must be specified a full name of the security group.""" + + offset: int + """Offset in results list""" + + tag_key: SequenceNotStr[str] + """Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2""" + + tag_key_value: str + """Optional. Filter by tag key-value pairs.""" diff --git a/src/gcore/types/cloud/security_group_rule.py b/src/gcore/types/cloud/security_group_rule.py new file mode 100644 index 00000000..aa717ba6 --- /dev/null +++ b/src/gcore/types/cloud/security_group_rule.py @@ -0,0 +1,83 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["SecurityGroupRule"] + + +class SecurityGroupRule(BaseModel): + id: str + """The ID of the security group rule""" + + created_at: datetime + """Datetime when the rule was created""" + + description: Optional[str] = None + """Rule description""" + + direction: Literal["egress", "ingress"] + """ + Ingress or egress, which is the direction in which the security group rule is + applied + """ + + ethertype: Optional[Literal["IPv4", "IPv6"]] = None + """ + Must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress + or egress rules. + """ + + port_range_max: Optional[int] = None + """The maximum port number in the range that is matched by the security group rule""" + + port_range_min: Optional[int] = None + """The minimum port number in the range that is matched by the security group rule""" + + protocol: Optional[ + Literal[ + "ah", + "any", + "dccp", + "egp", + "esp", + "gre", + "icmp", + "igmp", + "ipencap", + "ipip", + "ipv6-encap", + "ipv6-frag", + "ipv6-icmp", + "ipv6-nonxt", + "ipv6-opts", + "ipv6-route", + "ospf", + "pgm", + "rsvp", + "sctp", + "tcp", + "udp", + "udplite", + "vrrp", + ] + ] = None + """Protocol""" + + remote_group_id: Optional[str] = None + """The remote group UUID to associate with this security group rule""" + + remote_ip_prefix: Optional[str] = None + """The remote IP prefix that is matched by this security group rule""" + + revision_number: int + """The revision number of the resource""" + + security_group_id: str + """The security group ID to associate with this security group rule""" + + updated_at: datetime + """Datetime when the rule was last updated""" diff --git a/src/gcore/types/cloud/security_group_update_params.py b/src/gcore/types/cloud/security_group_update_params.py new file mode 100644 index 00000000..a5e34df0 --- /dev/null +++ b/src/gcore/types/cloud/security_group_update_params.py @@ -0,0 +1,109 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, TypedDict + +from .tag_update_map_param import TagUpdateMapParam + +__all__ = ["SecurityGroupUpdateParams", "Rule"] + + +class SecurityGroupUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + description: str + """Security group description""" + + name: str + """Name""" + + rules: Iterable[Rule] + """Security group rules""" + + tags: Optional[TagUpdateMapParam] + """Update key-value tags using JSON Merge Patch semantics (RFC 7386). + + Provide key-value pairs to add or update tags. Set tag values to `null` to + remove tags. Unspecified tags remain unchanged. Read-only tags are always + preserved and cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + """ + + +class Rule(TypedDict, total=False): + description: str + """Security grpup rule description""" + + direction: Literal["egress", "ingress"] + """ + Ingress or egress, which is the direction in which the security group rule is + applied + """ + + ethertype: Literal["IPv4", "IPv6"] + """ + Must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress + or egress rules. + """ + + port_range_max: int + """The maximum port number in the range that is matched by the security group rule""" + + port_range_min: int + """The minimum port number in the range that is matched by the security group rule""" + + protocol: Literal[ + "ah", + "any", + "dccp", + "egp", + "esp", + "gre", + "icmp", + "igmp", + "ipencap", + "ipip", + "ipv6-encap", + "ipv6-frag", + "ipv6-icmp", + "ipv6-nonxt", + "ipv6-opts", + "ipv6-route", + "ospf", + "pgm", + "rsvp", + "sctp", + "tcp", + "udp", + "udplite", + "vrrp", + ] + """Protocol""" + + remote_group_id: str + """The remote group UUID to associate with this security group rule""" + + remote_ip_prefix: str + """The remote IP prefix that is matched by this security group rule""" diff --git a/src/gcore/types/cloud/security_groups/__init__.py b/src/gcore/types/cloud/security_groups/__init__.py new file mode 100644 index 00000000..832f1d77 --- /dev/null +++ b/src/gcore/types/cloud/security_groups/__init__.py @@ -0,0 +1,6 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .rule_create_params import RuleCreateParams as RuleCreateParams +from .rule_replace_params import RuleReplaceParams as RuleReplaceParams diff --git a/src/gcore/types/cloud/security_groups/rule_create_params.py b/src/gcore/types/cloud/security_groups/rule_create_params.py new file mode 100644 index 00000000..46fdd411 --- /dev/null +++ b/src/gcore/types/cloud/security_groups/rule_create_params.py @@ -0,0 +1,67 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RuleCreateParams"] + + +class RuleCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + direction: Required[Literal["egress", "ingress"]] + """ + Ingress or egress, which is the direction in which the security group is applied + """ + + description: str + """Rule description""" + + ethertype: Literal["IPv4", "IPv6"] + """Ether type""" + + port_range_max: Optional[int] + """The maximum port number in the range that is matched by the security group rule""" + + port_range_min: Optional[int] + """The minimum port number in the range that is matched by the security group rule""" + + protocol: Literal[ + "ah", + "any", + "dccp", + "egp", + "esp", + "gre", + "icmp", + "igmp", + "ipencap", + "ipip", + "ipv6-encap", + "ipv6-frag", + "ipv6-icmp", + "ipv6-nonxt", + "ipv6-opts", + "ipv6-route", + "ospf", + "pgm", + "rsvp", + "sctp", + "tcp", + "udp", + "udplite", + "vrrp", + ] + """Protocol""" + + remote_group_id: str + """The remote group UUID to associate with this security group""" + + remote_ip_prefix: Optional[str] + """The remote IP prefix that is matched by this security group rule""" diff --git a/src/gcore/types/cloud/security_groups/rule_replace_params.py b/src/gcore/types/cloud/security_groups/rule_replace_params.py new file mode 100644 index 00000000..55d7a2ca --- /dev/null +++ b/src/gcore/types/cloud/security_groups/rule_replace_params.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RuleReplaceParams"] + + +class RuleReplaceParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + direction: Required[Literal["egress", "ingress"]] + """ + Ingress or egress, which is the direction in which the security group rule is + applied + """ + + security_group_id: Required[str] + """Parent security group of this rule""" + + description: str + """Rule description""" + + ethertype: Optional[Literal["IPv4", "IPv6"]] + """ + Must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress + or egress rules. + """ + + port_range_max: Optional[int] + """The maximum port number in the range that is matched by the security group rule""" + + port_range_min: Optional[int] + """The minimum port number in the range that is matched by the security group rule""" + + protocol: Literal[ + "ah", + "any", + "dccp", + "egp", + "esp", + "gre", + "icmp", + "igmp", + "ipencap", + "ipip", + "ipv6-encap", + "ipv6-frag", + "ipv6-icmp", + "ipv6-nonxt", + "ipv6-opts", + "ipv6-route", + "ospf", + "pgm", + "rsvp", + "sctp", + "tcp", + "udp", + "udplite", + "vrrp", + ] + """Protocol""" + + remote_group_id: Optional[str] + """The remote group UUID to associate with this security group rule""" + + remote_ip_prefix: Optional[str] + """The remote IP prefix that is matched by this security group rule""" diff --git a/src/gcore/types/cloud/session_persistence.py b/src/gcore/types/cloud/session_persistence.py new file mode 100644 index 00000000..e24317d3 --- /dev/null +++ b/src/gcore/types/cloud/session_persistence.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .lb_session_persistence_type import LbSessionPersistenceType + +__all__ = ["SessionPersistence"] + + +class SessionPersistence(BaseModel): + type: LbSessionPersistenceType + """Session persistence type""" + + cookie_name: Optional[str] = None + """Should be set if app cookie or http cookie is used""" + + persistence_granularity: Optional[str] = None + """Subnet mask if `source_ip` is used. For UDP ports only""" + + persistence_timeout: Optional[int] = None + """Session persistence timeout. For UDP ports only""" diff --git a/src/gcore/types/cloud/snapshot.py b/src/gcore/types/cloud/snapshot.py new file mode 100644 index 00000000..ac5ca594 --- /dev/null +++ b/src/gcore/types/cloud/snapshot.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from .tag import Tag +from ..._models import BaseModel + +__all__ = ["Snapshot"] + + +class Snapshot(BaseModel): + id: str + """Snapshot ID""" + + created_at: datetime + """Datetime when the snapshot was created""" + + creator_task_id: str + """Task that created this entity""" + + description: Optional[str] = None + """Snapshot description""" + + name: str + """Snapshot name""" + + project_id: int + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + size: int + """Snapshot size, GiB""" + + status: Literal[ + "available", + "backing-up", + "creating", + "deleted", + "deleting", + "error", + "error_deleting", + "restoring", + "unmanaging", + ] + """Snapshot status""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + updated_at: datetime + """Datetime when the snapshot was last updated""" + + volume_id: str + """ID of the volume this snapshot was made from""" diff --git a/src/gcore/types/cloud/ssh_key.py b/src/gcore/types/cloud/ssh_key.py new file mode 100644 index 00000000..1430a38d --- /dev/null +++ b/src/gcore/types/cloud/ssh_key.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["SSHKey"] + + +class SSHKey(BaseModel): + id: str + """SSH key ID""" + + created_at: Optional[datetime] = None + """SSH key creation time""" + + fingerprint: str + """Fingerprint""" + + name: str + """SSH key name""" + + project_id: Optional[int] = None + """Project ID""" + + public_key: str + """The public part of an SSH key is the shareable portion of an SSH key pair. + + It can be safely sent to servers or services to grant access. It does not + contain sensitive information. + """ + + shared_in_project: bool + """SSH key will be visible to all users in the project""" + + state: Literal["ACTIVE", "DELETING"] + """SSH key state""" diff --git a/src/gcore/types/cloud/ssh_key_create_params.py b/src/gcore/types/cloud/ssh_key_create_params.py new file mode 100644 index 00000000..65008f58 --- /dev/null +++ b/src/gcore/types/cloud/ssh_key_create_params.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["SSHKeyCreateParams"] + + +class SSHKeyCreateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + name: Required[str] + """SSH key name""" + + public_key: str + """The public part of an SSH key is the shareable portion of an SSH key pair. + + It can be safely sent to servers or services to grant access. It does not + contain sensitive information. + + - If you’re uploading your own key, provide the public part here (usually found + in a file like `id_ed25519.pub`). + - If you want the platform to generate an Ed25519 key pair for you, leave this + field empty — the system will return the private key in the response **once + only**. + """ + + shared_in_project: bool + """SSH key is shared with all users in the project""" diff --git a/src/gcore/types/cloud/ssh_key_created.py b/src/gcore/types/cloud/ssh_key_created.py new file mode 100644 index 00000000..c889ff5a --- /dev/null +++ b/src/gcore/types/cloud/ssh_key_created.py @@ -0,0 +1,53 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["SSHKeyCreated"] + + +class SSHKeyCreated(BaseModel): + id: str + """SSH key ID""" + + created_at: datetime + """SSH key creation time""" + + fingerprint: str + """Fingerprint""" + + name: str + """SSH key name""" + + private_key: Optional[str] = None + """The private part of an SSH key is the confidential portion of the key pair. + + It should never be shared or exposed. This key is used to prove your identity + when connecting to a server. + + If you omit the `public_key`, the platform will generate a key for you. The + `private_key` will be returned **once** in the API response. Be sure to save it + securely, as it cannot be retrieved again later. + + Best practice: Save the private key to a secure location on your machine (e.g., + `~/.ssh/id_ed25519`) and set the file permissions to be readable only by you. + """ + + project_id: int + """Project ID""" + + public_key: str + """The public part of an SSH key is the shareable portion of an SSH key pair. + + It can be safely sent to servers or services to grant access. It does not + contain sensitive information. + """ + + shared_in_project: bool + """SSH key will be visible to all users in the project""" + + state: Literal["ACTIVE", "DELETING"] + """SSH key state""" diff --git a/src/gcore/types/cloud/ssh_key_list_params.py b/src/gcore/types/cloud/ssh_key_list_params.py new file mode 100644 index 00000000..6082d012 --- /dev/null +++ b/src/gcore/types/cloud/ssh_key_list_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["SSHKeyListParams"] + + +class SSHKeyListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + limit: int + """Maximum number of SSH keys to return""" + + name: str + """SSH key name. + + Partial substring match. Example: `name=abc` matches any key containing `abc` in + name. + """ + + offset: int + """Offset for pagination""" + + order_by: Literal["created_at.asc", "created_at.desc", "name.asc", "name.desc"] + """Sort order for the SSH keys""" diff --git a/src/gcore/types/cloud/ssh_key_update_params.py b/src/gcore/types/cloud/ssh_key_update_params.py new file mode 100644 index 00000000..5efc271e --- /dev/null +++ b/src/gcore/types/cloud/ssh_key_update_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["SSHKeyUpdateParams"] + + +class SSHKeyUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + shared_in_project: Required[bool] + """Share your ssh key with all users in the project""" diff --git a/src/gcore/types/cloud/subnet.py b/src/gcore/types/cloud/subnet.py new file mode 100644 index 00000000..d6f0aece --- /dev/null +++ b/src/gcore/types/cloud/subnet.py @@ -0,0 +1,87 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from .tag import Tag +from .route import Route +from ..._models import BaseModel +from .ip_version import IPVersion + +__all__ = ["Subnet"] + + +class Subnet(BaseModel): + cidr: str + """CIDR""" + + created_at: datetime + """Datetime when the subnet was created""" + + enable_dhcp: bool + """True if DHCP should be enabled""" + + ip_version: IPVersion + """IP version""" + + name: str + """Subnet name""" + + network_id: str + """Network ID""" + + project_id: int + """Project ID""" + + region: str + """Region name""" + + region_id: int + """Region ID""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + updated_at: datetime + """Datetime when the subnet was last updated""" + + id: Optional[str] = None + """Subnet id.""" + + available_ips: Optional[int] = None + """Number of available ips in subnet""" + + creator_task_id: Optional[str] = None + """Task that created this entity""" + + dns_nameservers: Optional[List[str]] = None + """List IP addresses of a DNS resolver reachable from the network""" + + gateway_ip: Optional[str] = None + """Default GW IPv4 address, advertised in DHCP routes of this subnet. + + If null, no gateway is advertised by this subnet. + """ + + has_router: Optional[bool] = None + """Deprecated. Always returns `false`.""" + + host_routes: Optional[List[Route]] = None + """List of custom static routes to advertise via DHCP.""" + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + total_ips: Optional[int] = None + """Total number of ips in subnet""" diff --git a/src/gcore/types/cloud/tag.py b/src/gcore/types/cloud/tag.py new file mode 100644 index 00000000..9ee9fdba --- /dev/null +++ b/src/gcore/types/cloud/tag.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["Tag"] + + +class Tag(BaseModel): + """ + A tag is a key-value pair that can be associated with a resource, + enabling efficient filtering and grouping for better organization and management. + Some tags are read-only and cannot be modified by the user. + Tags are also integrated with cost reports, allowing cost data to be filtered based on tag keys or values. + """ + + key: str + """Tag key. + + Maximum 255 characters. Cannot contain spaces, tabs, newlines, empty string or + '=' character. + """ + + read_only: bool + """If true, the tag is read-only and cannot be modified by the user""" + + value: str + """Tag value. + + Maximum 255 characters. Cannot contain spaces, tabs, newlines, empty string or + '=' character. + """ diff --git a/src/gcore/types/cloud/tag_update_map_param.py b/src/gcore/types/cloud/tag_update_map_param.py new file mode 100644 index 00000000..9a70575e --- /dev/null +++ b/src/gcore/types/cloud/tag_update_map_param.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypeAlias + +__all__ = ["TagUpdateMapParam"] + +TagUpdateMapParam: TypeAlias = object diff --git a/src/gcore/types/cloud/task.py b/src/gcore/types/cloud/task.py new file mode 100644 index 00000000..c028eb40 --- /dev/null +++ b/src/gcore/types/cloud/task.py @@ -0,0 +1,198 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["Task", "CreatedResources"] + + +class CreatedResources(BaseModel): + """If the task creates resources, this field will contain their IDs""" + + ai_clusters: Optional[List[str]] = None + """IDs of created AI clusters""" + + api_keys: Optional[List[str]] = None + """IDs of created API keys""" + + caas_containers: Optional[List[str]] = None + """IDs of created CaaS containers""" + + ddos_profiles: Optional[List[int]] = None + """IDs of created ddos protection profiles""" + + faas_functions: Optional[List[str]] = None + """IDs of created FaaS functions""" + + faas_namespaces: Optional[List[str]] = None + """IDs of created FaaS namespaces""" + + file_shares: Optional[List[str]] = None + """IDs of created file shares""" + + floatingips: Optional[List[str]] = None + """IDs of created floating IPs""" + + healthmonitors: Optional[List[str]] = None + """IDs of created health monitors""" + + images: Optional[List[str]] = None + """IDs of created images""" + + inference_instances: Optional[List[str]] = None + """IDs of created inference instances""" + + instances: Optional[List[str]] = None + """IDs of created instances""" + + k8s_clusters: Optional[List[str]] = None + """IDs of created Kubernetes clusters""" + + k8s_pools: Optional[List[str]] = None + """IDs of created Kubernetes pools""" + + l7polices: Optional[List[str]] = None + """IDs of created L7 policies""" + + l7rules: Optional[List[str]] = None + """IDs of created L7 rules""" + + laas_topic: Optional[List[str]] = None + """IDs of created LaaS topics""" + + listeners: Optional[List[str]] = None + """IDs of created load balancer listeners""" + + loadbalancers: Optional[List[str]] = None + """IDs of created load balancers""" + + members: Optional[List[str]] = None + """IDs of created pool members""" + + networks: Optional[List[str]] = None + """IDs of created networks""" + + pools: Optional[List[str]] = None + """IDs of created load balancer pools""" + + ports: Optional[List[str]] = None + """IDs of created ports""" + + postgresql_clusters: Optional[List[str]] = None + """IDs of created postgres clusters""" + + projects: Optional[List[int]] = None + """IDs of created projects""" + + registry_registries: Optional[List[str]] = None + """IDs of created registry registries""" + + registry_users: Optional[List[str]] = None + """IDs of created registry users""" + + routers: Optional[List[str]] = None + """IDs of created routers""" + + secrets: Optional[List[str]] = None + """IDs of created secrets""" + + security_group_rules: Optional[List[str]] = None + """IDs of created security group rules""" + + security_groups: Optional[List[str]] = None + """IDs of created security groups""" + + servergroups: Optional[List[str]] = None + """IDs of created server groups""" + + snapshots: Optional[List[str]] = None + """IDs of created volume snapshots""" + + subnets: Optional[List[str]] = None + """IDs of created subnets""" + + volumes: Optional[List[str]] = None + """IDs of created volumes""" + + +class Task(BaseModel): + id: str + """The task ID""" + + created_on: Optional[str] = None + """Created timestamp""" + + state: Literal["ERROR", "FINISHED", "NEW", "RUNNING"] + """The task state""" + + task_type: str + """The task type""" + + user_id: int + """The user ID that initiated the task""" + + acknowledged_at: Optional[str] = None + """If task was acknowledged, this field stores acknowledge timestamp""" + + acknowledged_by: Optional[int] = None + """If task was acknowledged, this field stores `user_id` of the person""" + + client_id: Optional[int] = None + """The client ID""" + + created_resources: Optional[CreatedResources] = None + """If the task creates resources, this field will contain their IDs""" + + data: Optional[object] = None + """Task parameters""" + + detailed_state: Optional[ + Literal[ + "CLUSTER_CLEAN_UP", + "CLUSTER_REBUILD", + "CLUSTER_RESIZE", + "CLUSTER_RESUME", + "CLUSTER_SERVER_REBUILD", + "CLUSTER_SUSPEND", + "ERROR", + "FINISHED", + "IPU_SERVERS", + "NETWORK", + "POPLAR_SERVERS", + "POST_DEPLOY_SETUP", + "VIPU_CONTROLLER", + ] + ] = None + """Task detailed state that is more specific to task type""" + + error: Optional[str] = None + """The error value""" + + finished_on: Optional[str] = None + """Finished timestamp""" + + job_id: Optional[str] = None + """Job ID""" + + lifecycle_policy_id: Optional[int] = None + """Lifecycle policy ID""" + + project_id: Optional[int] = None + """The project ID""" + + region_id: Optional[int] = None + """The region ID""" + + request_id: Optional[str] = None + """The request ID""" + + schedule_id: Optional[str] = None + """Schedule ID""" + + updated_on: Optional[str] = None + """Last updated timestamp""" + + user_client_id: Optional[int] = None + """Client, specified in user's JWT""" diff --git a/src/gcore/types/cloud/task_acknowledge_all_params.py b/src/gcore/types/cloud/task_acknowledge_all_params.py new file mode 100644 index 00000000..4637c9b7 --- /dev/null +++ b/src/gcore/types/cloud/task_acknowledge_all_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["TaskAcknowledgeAllParams"] + + +class TaskAcknowledgeAllParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" diff --git a/src/gcore/types/cloud/task_id_list.py b/src/gcore/types/cloud/task_id_list.py new file mode 100644 index 00000000..a4ad68d2 --- /dev/null +++ b/src/gcore/types/cloud/task_id_list.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel + +__all__ = ["TaskIDList"] + + +class TaskIDList(BaseModel): + tasks: List[str] + """List of task IDs representing asynchronous operations. + + Use these IDs to monitor operation progress: + + - `GET /v1/tasks/{task_id}` - Check individual task status and details Poll task + status until completion (`FINISHED`/`ERROR`) before proceeding with dependent + operations. + """ diff --git a/src/gcore/types/cloud/task_list_params.py b/src/gcore/types/cloud/task_list_params.py new file mode 100644 index 00000000..f7337af9 --- /dev/null +++ b/src/gcore/types/cloud/task_list_params.py @@ -0,0 +1,114 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from datetime import datetime +from typing_extensions import Literal, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["TaskListParams"] + + +class TaskListParams(TypedDict, total=False): + from_timestamp: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """ISO formatted datetime string. + + Filter the tasks by creation date greater than or equal to `from_timestamp` + """ + + is_acknowledged: bool + """Filter the tasks by their acknowledgement status""" + + limit: int + """Limit the number of returned tasks. + + Falls back to default of 10 if not specified. Limited by max limit value of 1000 + """ + + offset: int + """Offset value is used to exclude the first set of records from the result""" + + order_by: Literal["asc", "desc"] + """Sorting by creation date. Oldest first, or most recent first""" + + project_id: Iterable[int] + """The project ID to filter the tasks by project. + + Supports multiple values of kind key=value1&key=value2 + """ + + region_id: Iterable[int] + """The region ID to filter the tasks by region. + + Supports multiple values of kind key=value1&key=value2 + """ + + sorting: Literal["asc", "desc"] + """(DEPRECATED Use 'order_by' instead) Sorting by creation date. + + Oldest first, or most recent first + """ + + state: List[Literal["ERROR", "FINISHED", "NEW", "RUNNING"]] + """Filter the tasks by state. + + Supports multiple values of kind key=value1&key=value2 + """ + + task_type: str + """ + Filter the tasks by their type one of ['activate_ddos_profile', + 'attach_bm_to_reserved_fixed_ip', 'attach_vm_interface', + 'attach_vm_to_reserved_fixed_ip', 'attach_volume', 'create_ai_cluster_gpu', + 'create_bm', 'create_caas_container', 'create_dbaas_postgres_cluster', + 'create_ddos_profile', 'create_faas_function', 'create_faas_namespace', + 'create_fip', 'create_gpu_virtual_cluster', 'create_image', + 'create_inference_application', 'create_inference_instance', + 'create_k8s_cluster_pool_v2', 'create_k8s_cluster_v2', 'create_l7policy', + 'create_l7rule', 'create_lblistener', 'create_lbmember', 'create_lbpool', + 'create_lbpool_health_monitor', 'create_loadbalancer', 'create_network', + 'create_reserved_fixed_ip', 'create_router', 'create_secret', + 'create_security_group', 'create_security_group_rule', 'create_servergroup', + 'create_sfs', 'create_snapshot', 'create_subnet', 'create_vm', 'create_volume', + 'deactivate_ddos_profile', 'delete_ai_cluster_gpu', 'delete_caas_container', + 'delete_dbaas_postgres_cluster', 'delete_ddos_profile', 'delete_faas_function', + 'delete_faas_namespace', 'delete_fip', 'delete_gpu_virtual_cluster', + 'delete_gpu_virtual_server', 'delete_image', 'delete_inference_application', + 'delete_inference_instance', 'delete_k8s_cluster_pool_v2', + 'delete_k8s_cluster_v2', 'delete_l7policy', 'delete_l7rule', + 'delete_lblistener', 'delete_lbmember', 'delete_lbmetadata', 'delete_lbpool', + 'delete_loadbalancer', 'delete_network', 'delete_project', + 'delete_reserved_fixed_ip', 'delete_router', 'delete_secret', + 'delete_security_group_rule', 'delete_servergroup', 'delete_sfs', + 'delete_snapshot', 'delete_subnet', 'delete_vm', 'delete_volume', + 'detach_vm_interface', 'detach_volume', 'download_image', + 'downscale_ai_cluster_gpu', 'downscale_gpu_virtual_cluster', 'extend_sfs', + 'extend_volume', 'failover_loadbalancer', 'hard_reboot_gpu_baremetal_server', + 'hard_reboot_gpu_virtual_cluster', 'hard_reboot_gpu_virtual_server', + 'hard_reboot_vm', 'patch_caas_container', 'patch_dbaas_postgres_cluster', + 'patch_faas_function', 'patch_faas_namespace', 'patch_lblistener', + 'patch_lbpool', 'put_into_server_group', 'put_l7rule', 'rebuild_bm', + 'rebuild_gpu_baremetal_cluster', 'rebuild_gpu_baremetal_node', + 'rebuild_gpu_baremetal_server', 'remove_from_server_group', + 'replace_lbmetadata', 'resize_k8s_cluster_v2', 'resize_loadbalancer', + 'resize_vm', 'resume_vm', 'revert_volume', 'soft_reboot_gpu_baremetal_server', + 'soft_reboot_gpu_virtual_cluster', 'soft_reboot_gpu_virtual_server', + 'soft_reboot_vm', 'start_gpu_baremetal_server', 'start_gpu_virtual_cluster', + 'start_gpu_virtual_server', 'start_vm', 'stop_gpu_baremetal_server', + 'stop_gpu_virtual_cluster', 'stop_gpu_virtual_server', 'stop_vm', 'suspend_vm', + 'sync_private_flavors', 'update_ddos_profile', 'update_floating_ip', + 'update_inference_application', 'update_inference_instance', + 'update_k8s_cluster_v2', 'update_l7policy', 'update_lbmetadata', + 'update_loadbalancer', 'update_port_allowed_address_pairs', 'update_router', + 'update_security_group', 'update_sfs', 'update_tags_gpu_virtual_cluster', + 'upgrade_k8s_cluster_v2', 'upscale_ai_cluster_gpu', + 'upscale_gpu_virtual_cluster'] + """ + + to_timestamp: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """ISO formatted datetime string. + + Filter the tasks by creation date less than or equal to `to_timestamp` + """ diff --git a/src/gcore/types/cloud/usage_report.py b/src/gcore/types/cloud/usage_report.py new file mode 100644 index 00000000..659a5421 --- /dev/null +++ b/src/gcore/types/cloud/usage_report.py @@ -0,0 +1,1702 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "UsageReport", + "Resource", + "ResourceResourceAIClusterSerializer", + "ResourceResourceAIVirtualClusterSerializer", + "ResourceResourceBaremetalSerializer", + "ResourceResourceBasicVmSerializer", + "ResourceResourceBackupSerializer", + "ResourceResourceContainerSerializer", + "ResourceResourceEgressTrafficSerializer", + "ResourceResourceExternalIPSerializer", + "ResourceResourceFileShareSerializer", + "ResourceResourceFloatingIPSerializer", + "ResourceResourceFunctionsSerializer", + "ResourceResourceFunctionCallsSerializer", + "ResourceResourceFunctionEgressTrafficSerializer", + "ResourceResourceImagesSerializer", + "ResourceResourceInferenceSerializer", + "ResourceResourceInstanceSerializer", + "ResourceResourceLoadBalancerSerializer", + "ResourceResourceLogIndexSerializer", + "ResourceResourceSnapshotSerializer", + "ResourceResourceVolumeSerializer", + "ResourceResourceDbaasPostgreSQLPoolerSerializer", + "ResourceResourceDbaasPostgreSQLMemorySerializer", + "ResourceResourceDbaasPostgreSQLPublicNetworkSerializer", + "ResourceResourceDbaasPostgreSqlcpuSerializer", + "ResourceResourceDbaasPostgreSQLVolumeSerializer", + "Total", + "TotalTotalAIClusterReportItemSerializer", + "TotalTotalAIVirtualClusterReportItemSerializer", + "TotalTotalBaremetalReportItemSerializer", + "TotalTotalBasicVmReportItemSerializer", + "TotalTotalContainerReportItemSerializer", + "TotalTotalEgressTrafficReportItemSerializer", + "TotalTotalExternalIPReportItemSerializer", + "TotalTotalFileShareReportItemSerializer", + "TotalTotalFloatingIPReportItemSerializer", + "TotalTotalFunctionsReportItemSerializer", + "TotalTotalFunctionCallsReportItemSerializer", + "TotalTotalFunctionEgressTrafficReportItemSerializer", + "TotalTotalImagesReportItemSerializer", + "TotalTotalInferenceReportItemSerializer", + "TotalTotalInstanceReportItemSerializer", + "TotalTotalLoadBalancerReportItemSerializer", + "TotalTotalLogIndexReportItemSerializer", + "TotalTotalSnapshotReportItemSerializer", + "TotalTotalVolumeReportItemSerializer", + "TotalTotalDbaasPostgreSQLPoolerReportItemSerializer", + "TotalTotalDbaasPostgreSQLMemoryReportItemSerializer", + "TotalTotalDbaasPostgreSQLPublicNetworkReportItemSerializer", + "TotalTotalDbaasPostgreSqlcpuReportItemSerializer", + "TotalTotalDbaasPostgreSQLVolumeReportItemSerializer", +] + + +class ResourceResourceAIClusterSerializer(BaseModel): + """ + These properties are common for all individual AI clusters + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the Baremetal GPU cluster""" + + last_name: str + """Name of the AI cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["ai_cluster"] + + uuid: str + """UUID of the Baremetal GPU cluster""" + + +class ResourceResourceAIVirtualClusterSerializer(BaseModel): + """ + These properties are common for all individual AI Virtual clusters + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the Virtual GPU cluster""" + + last_name: str + """Name of the AI cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["ai_virtual_cluster"] + + uuid: str + """UUID of the Virtual GPU cluster""" + + +class ResourceResourceBaremetalSerializer(BaseModel): + """ + These properties are common for all individual bare metal servers + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the bare metal server""" + + last_name: str + """Name of the bare metal server""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["baremetal"] + + uuid: str + """UUID of the bare metal server""" + + +class ResourceResourceBasicVmSerializer(BaseModel): + """ + These properties are common for all individual basic VMs + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the basic VM""" + + last_name: str + """Name of the basic VM""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["basic_vm"] + + uuid: str + """UUID of the basic VM""" + + +class ResourceResourceBackupSerializer(BaseModel): + """ + These properties are common for all individual backups + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the backup""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + last_size: int + """Size of the backup in bytes""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + schedule_id: str + """ID of the backup schedule""" + + source_volume_uuid: str + """UUID of the source volume""" + + type: Literal["backup"] + + uuid: str + """UUID of the backup""" + + +class ResourceResourceContainerSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GBS"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the container""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["containers"] + + uuid: str + """UUID of the container""" + + +class ResourceResourceEgressTrafficSerializer(BaseModel): + """ + These properties are common for all individual egress traffic + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["bytes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + instance_name: Optional[str] = None + """Name of the instance""" + + instance_type: Literal["baremetal", "vm"] + """Type of the instance""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + port_id: str + """ID of the port the traffic is associated with""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: str + """Unit of size""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["egress_traffic"] + + vm_id: str + """ID of the bare metal server the traffic is associated with""" + + +class ResourceResourceExternalIPSerializer(BaseModel): + """ + These properties are common for all individual external IPs + in all cost and usage reports results (but not in totals) + """ + + attached_to_vm: Optional[str] = None + """ID of the VM the IP is attached to""" + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + ip_address: str + """IP address""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + network_id: str + """ID of the network the IP is attached to""" + + port_id: str + """ID of the port the IP is associated with""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + subnet_id: str + """ID of the subnet the IP is attached to""" + + type: Literal["external_ip"] + + +class ResourceResourceFileShareSerializer(BaseModel): + """ + These properties are common for all individual file shares + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + file_share_type: str + """Type of the file share""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the file share""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + last_size: int + """Size of the file share in bytes""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: Literal["GiB"] + """Unit of size""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["file_share"] + + uuid: str + """UUID of the file share""" + + +class ResourceResourceFloatingIPSerializer(BaseModel): + """ + These properties are common for all individual floating IPs + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + ip_address: str + """IP address""" + + last_name: str + """Name of the floating IP""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["floatingip"] + + uuid: str + """UUID of the floating IP""" + + +class ResourceResourceFunctionsSerializer(BaseModel): + """ + These properties are common for all individual functions + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GBS"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the function""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions"] + + uuid: str + """UUID of the function""" + + +class ResourceResourceFunctionCallsSerializer(BaseModel): + """ + These properties are common for all individual function calls + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["MLS"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the function call""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions_calls"] + + uuid: str + """UUID of the function call""" + + +class ResourceResourceFunctionEgressTrafficSerializer(BaseModel): + """ + These properties are common for all individual function egress traffic + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GB"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the function egress traffic""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions_traffic"] + + uuid: str + """UUID of the function egress traffic""" + + +class ResourceResourceImagesSerializer(BaseModel): + """ + These properties are common for all individual images + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the image""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + last_size: int + """Size of the image in bytes""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: Literal["bytes"] + """Unit of size""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["image"] + + uuid: str + """UUID of the image""" + + +class ResourceResourceInferenceSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: str + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the inference deployment""" + + last_name: str + """Name of the inference deployment""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["inference"] + + uuid: str + """UUID of the inference deployment""" + + +class ResourceResourceInstanceSerializer(BaseModel): + """ + These properties are common for all individual instances + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the instance""" + + last_name: str + """Name of the instance""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["instance"] + + uuid: str + """UUID of the instance""" + + +class ResourceResourceLoadBalancerSerializer(BaseModel): + """ + These properties are common for all individual load balancers + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + flavor: str + """Flavor of the load balancer""" + + last_name: str + """Name of the load balancer""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["load_balancer"] + + uuid: str + """UUID of the load balancer""" + + +class ResourceResourceLogIndexSerializer(BaseModel): + """ + These properties are common for all individual log indexes + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the log index""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + last_size: int + """Size of the log index in bytes""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: str + """Unit of size""" + + type: Literal["log_index"] + + uuid: Optional[str] = None + """UUID of the log index""" + + +class ResourceResourceSnapshotSerializer(BaseModel): + """ + These properties are common for all individual snapshots + in all cost and usage reports results (but not in totals) + """ + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the snapshot""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + last_size: int + """Size of the snapshot in bytes""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: str + """Unit of size""" + + source_volume_uuid: str + """UUID of the source volume""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["snapshot"] + + uuid: str + """UUID of the snapshot""" + + volume_type: str + """Type of the volume""" + + +class ResourceResourceVolumeSerializer(BaseModel): + """ + These properties are common for all individual volumes + in all cost and usage reports results (but not in totals) + """ + + attached_to_vm: Optional[str] = None + """ID of the VM the volume is attached to""" + + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the volume""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + last_size: int + """Size of the volume in bytes""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: str + """Unit of size""" + + tags: Optional[List[Dict[str, str]]] = None + """List of tags""" + + type: Literal["volume"] + + uuid: str + """UUID of the volume""" + + volume_type: str + """Type of the volume""" + + +class ResourceResourceDbaasPostgreSQLPoolerSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_connection_pooler"] + + uuid: str + """UUID of the cluster""" + + +class ResourceResourceDbaasPostgreSQLMemorySerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_memory"] + + uuid: str + """UUID of the cluster""" + + +class ResourceResourceDbaasPostgreSQLPublicNetworkSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_public_network"] + + uuid: str + """UUID of the cluster""" + + +class ResourceResourceDbaasPostgreSqlcpuSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_cpu"] + + uuid: str + """UUID of the cluster""" + + +class ResourceResourceDbaasPostgreSQLVolumeSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + first_seen: datetime + """First time the resource was seen in the given period""" + + last_name: str + """Name of the cluster""" + + last_seen: datetime + """Last time the resource was seen in the given period""" + + project_id: int + """ID of the project the resource belongs to""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + size_unit: str + """Unit of size""" + + type: Literal["dbaas_postgresql_volume"] + + uuid: str + """UUID of the cluster""" + + volume_type: str + """Type of the volume""" + + +Resource: TypeAlias = Annotated[ + Union[ + ResourceResourceAIClusterSerializer, + ResourceResourceAIVirtualClusterSerializer, + ResourceResourceBaremetalSerializer, + ResourceResourceBasicVmSerializer, + ResourceResourceBackupSerializer, + ResourceResourceContainerSerializer, + ResourceResourceEgressTrafficSerializer, + ResourceResourceExternalIPSerializer, + ResourceResourceFileShareSerializer, + ResourceResourceFloatingIPSerializer, + ResourceResourceFunctionsSerializer, + ResourceResourceFunctionCallsSerializer, + ResourceResourceFunctionEgressTrafficSerializer, + ResourceResourceImagesSerializer, + ResourceResourceInferenceSerializer, + ResourceResourceInstanceSerializer, + ResourceResourceLoadBalancerSerializer, + ResourceResourceLogIndexSerializer, + ResourceResourceSnapshotSerializer, + ResourceResourceVolumeSerializer, + ResourceResourceDbaasPostgreSQLPoolerSerializer, + ResourceResourceDbaasPostgreSQLMemorySerializer, + ResourceResourceDbaasPostgreSQLPublicNetworkSerializer, + ResourceResourceDbaasPostgreSqlcpuSerializer, + ResourceResourceDbaasPostgreSQLVolumeSerializer, + ], + PropertyInfo(discriminator="type"), +] + + +class TotalTotalAIClusterReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + flavor: str + """Flavor of the Baremetal GPU cluster""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["ai_cluster"] + + +class TotalTotalAIVirtualClusterReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + flavor: str + """Flavor of the Virtual GPU cluster""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["ai_virtual_cluster"] + + +class TotalTotalBaremetalReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + flavor: str + """Flavor of the bare metal server""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["baremetal"] + + +class TotalTotalBasicVmReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + flavor: str + """Flavor of the basic VM""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["basic_vm"] + + +class TotalTotalContainerReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GBS"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["containers"] + + +class TotalTotalEgressTrafficReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["bytes"] + """Unit of billing value""" + + instance_type: Literal["baremetal", "vm"] + """Type of the instance""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["egress_traffic"] + + +class TotalTotalExternalIPReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["external_ip"] + + +class TotalTotalFileShareReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + file_share_type: str + """Type of the file share""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["file_share"] + + +class TotalTotalFloatingIPReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["floatingip"] + + +class TotalTotalFunctionsReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GBS"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions"] + + +class TotalTotalFunctionCallsReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["MLS"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions_calls"] + + +class TotalTotalFunctionEgressTrafficReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["GB"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["functions_traffic"] + + +class TotalTotalImagesReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["image"] + + +class TotalTotalInferenceReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: str + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["inference"] + + +class TotalTotalInstanceReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + flavor: str + """Flavor of the instance""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["instance"] + + +class TotalTotalLoadBalancerReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + flavor: str + """Flavor of the load balancer""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["load_balancer"] + + +class TotalTotalLogIndexReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["log_index"] + + +class TotalTotalSnapshotReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["snapshot"] + + volume_type: str + """Type of the volume""" + + +class TotalTotalVolumeReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["volume"] + + volume_type: str + """Type of the volume""" + + +class TotalTotalDbaasPostgreSQLPoolerReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_connection_pooler"] + + +class TotalTotalDbaasPostgreSQLMemoryReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_memory"] + + +class TotalTotalDbaasPostgreSQLPublicNetworkReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_public_network"] + + +class TotalTotalDbaasPostgreSqlcpuReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["minutes"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_cpu"] + + +class TotalTotalDbaasPostgreSQLVolumeReportItemSerializer(BaseModel): + billing_metric_name: str + """Name of the billing metric""" + + billing_value: float + """Value of the billing metric""" + + billing_value_unit: Literal["gbminutes"] + """Unit of billing value""" + + region: int + """Region ID""" + + region_id: int + """Region ID""" + + type: Literal["dbaas_postgresql_volume"] + + volume_type: str + """Type of the volume""" + + +Total: TypeAlias = Annotated[ + Union[ + TotalTotalAIClusterReportItemSerializer, + TotalTotalAIVirtualClusterReportItemSerializer, + TotalTotalBaremetalReportItemSerializer, + TotalTotalBasicVmReportItemSerializer, + TotalTotalContainerReportItemSerializer, + TotalTotalEgressTrafficReportItemSerializer, + TotalTotalExternalIPReportItemSerializer, + TotalTotalFileShareReportItemSerializer, + TotalTotalFloatingIPReportItemSerializer, + TotalTotalFunctionsReportItemSerializer, + TotalTotalFunctionCallsReportItemSerializer, + TotalTotalFunctionEgressTrafficReportItemSerializer, + TotalTotalImagesReportItemSerializer, + TotalTotalInferenceReportItemSerializer, + TotalTotalInstanceReportItemSerializer, + TotalTotalLoadBalancerReportItemSerializer, + TotalTotalLogIndexReportItemSerializer, + TotalTotalSnapshotReportItemSerializer, + TotalTotalVolumeReportItemSerializer, + TotalTotalDbaasPostgreSQLPoolerReportItemSerializer, + TotalTotalDbaasPostgreSQLMemoryReportItemSerializer, + TotalTotalDbaasPostgreSQLPublicNetworkReportItemSerializer, + TotalTotalDbaasPostgreSqlcpuReportItemSerializer, + TotalTotalDbaasPostgreSQLVolumeReportItemSerializer, + ], + PropertyInfo(discriminator="type"), +] + + +class UsageReport(BaseModel): + count: int + """Total count of the resources""" + + resources: List[Resource] + + totals: List[Total] diff --git a/src/gcore/types/cloud/usage_report_get_params.py b/src/gcore/types/cloud/usage_report_get_params.py new file mode 100644 index 00000000..6f5b1af2 --- /dev/null +++ b/src/gcore/types/cloud/usage_report_get_params.py @@ -0,0 +1,435 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable, Optional +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = [ + "UsageReportGetParams", + "SchemaFilter", + "SchemaFilterSchemaFilterSnapshotSerializer", + "SchemaFilterSchemaFilterInstanceSerializer", + "SchemaFilterSchemaFilterAIClusterSerializer", + "SchemaFilterSchemaFilterAIVirtualClusterSerializer", + "SchemaFilterSchemaFilterBasicVmSerializer", + "SchemaFilterSchemaFilterBaremetalSerializer", + "SchemaFilterSchemaFilterVolumeSerializer", + "SchemaFilterSchemaFilterFileShareSerializer", + "SchemaFilterSchemaFilterImageSerializer", + "SchemaFilterSchemaFilterFloatingIPSerializer", + "SchemaFilterSchemaFilterEgressTrafficSerializer", + "SchemaFilterSchemaFilterLoadBalancerSerializer", + "SchemaFilterSchemaFilterExternalIPSerializer", + "SchemaFilterSchemaFilterBackupSerializer", + "SchemaFilterSchemaFilterLogIndexSerializer", + "SchemaFilterSchemaFilterFunctionsSerializer", + "SchemaFilterSchemaFilterFunctionsCallsSerializer", + "SchemaFilterSchemaFilterFunctionsTrafficSerializer", + "SchemaFilterSchemaFilterContainersSerializer", + "SchemaFilterSchemaFilterInferenceSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer", + "SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer", + "Sorting", + "Tags", + "TagsCondition", +] + + +class UsageReportGetParams(TypedDict, total=False): + time_from: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """The start date of the report period (ISO 8601). + + The report starts from the beginning of this day in UTC. + """ + + time_to: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """The end date of the report period (ISO 8601). + + The report ends just before the beginning of this day in UTC. + """ + + enable_last_day: bool + """Expenses for the last specified day are taken into account. + + As the default, False. + """ + + limit: int + """The response resources limit. Defaults to 10.""" + + offset: int + """The response resources offset.""" + + projects: Optional[Iterable[int]] + """List of project IDs""" + + regions: Iterable[int] + """List of region IDs.""" + + schema_filter: SchemaFilter + """Extended filter for field filtering.""" + + sorting: Iterable[Sorting] + """List of sorting filters (JSON objects) fields: project. directions: asc, desc.""" + + tags: Tags + """Filter by tags""" + + types: List[ + Literal[ + "ai_cluster", + "ai_virtual_cluster", + "backup", + "baremetal", + "basic_vm", + "containers", + "dbaas_postgresql_connection_pooler", + "dbaas_postgresql_cpu", + "dbaas_postgresql_memory", + "dbaas_postgresql_public_network", + "dbaas_postgresql_volume", + "egress_traffic", + "external_ip", + "file_share", + "floatingip", + "functions", + "functions_calls", + "functions_traffic", + "image", + "inference", + "instance", + "load_balancer", + "log_index", + "snapshot", + "volume", + ] + ] + """List of resource types to be filtered in the report.""" + + +class SchemaFilterSchemaFilterSnapshotSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "source_volume_uuid", "type", "uuid", "volume_type"]] + """Field name to filter by""" + + type: Required[Literal["snapshot"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterInstanceSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["instance"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterAIClusterSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["ai_cluster"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterAIVirtualClusterSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["ai_virtual_cluster"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterBasicVmSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["basic_vm"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterBaremetalSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["baremetal"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterVolumeSerializer(TypedDict, total=False): + field: Required[Literal["attached_to_vm", "last_name", "last_size", "type", "uuid", "volume_type"]] + """Field name to filter by""" + + type: Required[Literal["volume"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFileShareSerializer(TypedDict, total=False): + field: Required[Literal["file_share_type", "last_name", "last_size", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["file_share"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterImageSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["image"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFloatingIPSerializer(TypedDict, total=False): + field: Required[Literal["ip_address", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["floatingip"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterEgressTrafficSerializer(TypedDict, total=False): + field: Required[Literal["instance_name", "instance_type", "port_id", "type", "vm_id"]] + """Field name to filter by""" + + type: Required[Literal["egress_traffic"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterLoadBalancerSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["load_balancer"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterExternalIPSerializer(TypedDict, total=False): + field: Required[Literal["attached_to_vm", "ip_address", "network_id", "port_id", "subnet_id", "type"]] + """Field name to filter by""" + + type: Required[Literal["external_ip"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterBackupSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "schedule_id", "source_volume_uuid", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["backup"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterLogIndexSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "last_size", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["log_index"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFunctionsSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["functions"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFunctionsCallsSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["functions_calls"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterFunctionsTrafficSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["functions_traffic"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterContainersSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["containers"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterInferenceSerializer(TypedDict, total=False): + field: Required[Literal["flavor", "last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["inference"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid", "volume_type"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_volume"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_public_network"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_cpu"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_memory"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +class SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer(TypedDict, total=False): + field: Required[Literal["last_name", "type", "uuid"]] + """Field name to filter by""" + + type: Required[Literal["dbaas_postgresql_connection_pooler"]] + + values: Required[SequenceNotStr[str]] + """List of field values to filter""" + + +SchemaFilter: TypeAlias = Union[ + SchemaFilterSchemaFilterSnapshotSerializer, + SchemaFilterSchemaFilterInstanceSerializer, + SchemaFilterSchemaFilterAIClusterSerializer, + SchemaFilterSchemaFilterAIVirtualClusterSerializer, + SchemaFilterSchemaFilterBasicVmSerializer, + SchemaFilterSchemaFilterBaremetalSerializer, + SchemaFilterSchemaFilterVolumeSerializer, + SchemaFilterSchemaFilterFileShareSerializer, + SchemaFilterSchemaFilterImageSerializer, + SchemaFilterSchemaFilterFloatingIPSerializer, + SchemaFilterSchemaFilterEgressTrafficSerializer, + SchemaFilterSchemaFilterLoadBalancerSerializer, + SchemaFilterSchemaFilterExternalIPSerializer, + SchemaFilterSchemaFilterBackupSerializer, + SchemaFilterSchemaFilterLogIndexSerializer, + SchemaFilterSchemaFilterFunctionsSerializer, + SchemaFilterSchemaFilterFunctionsCallsSerializer, + SchemaFilterSchemaFilterFunctionsTrafficSerializer, + SchemaFilterSchemaFilterContainersSerializer, + SchemaFilterSchemaFilterInferenceSerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer, + SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer, + SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer, +] + + +class Sorting(TypedDict, total=False): + billing_value: Literal["asc", "desc"] + + first_seen: Literal["asc", "desc"] + + last_name: Literal["asc", "desc"] + + last_seen: Literal["asc", "desc"] + + project: Literal["asc", "desc"] + + region: Literal["asc", "desc"] + + type: Literal["asc", "desc"] + + +class TagsCondition(TypedDict, total=False): + key: str + """The name of the tag to filter (e.g., 'os_version').""" + + strict: bool + """Determines how strictly the tag value must match the specified value. + + If true, the tag value must exactly match the given value. If false, a less + strict match (e.g., partial or case-insensitive match) may be applied. + """ + + value: str + """The value of the tag to filter (e.g., '22.04').""" + + +class Tags(TypedDict, total=False): + """Filter by tags""" + + conditions: Required[Iterable[TagsCondition]] + """A list of tag filtering conditions defining how tags should match.""" + + condition_type: Literal["AND", "OR"] + """Specifies whether conditions are combined using OR (default) or AND logic.""" diff --git a/src/gcore/types/cloud/users/__init__.py b/src/gcore/types/cloud/users/__init__.py new file mode 100644 index 00000000..0fb51dca --- /dev/null +++ b/src/gcore/types/cloud/users/__init__.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .role_assignment import RoleAssignment as RoleAssignment +from .role_assignment_list_params import RoleAssignmentListParams as RoleAssignmentListParams +from .role_assignment_create_params import RoleAssignmentCreateParams as RoleAssignmentCreateParams +from .role_assignment_update_params import RoleAssignmentUpdateParams as RoleAssignmentUpdateParams +from .role_assignment_updated_deleted import RoleAssignmentUpdatedDeleted as RoleAssignmentUpdatedDeleted diff --git a/src/gcore/types/cloud/users/role_assignment.py b/src/gcore/types/cloud/users/role_assignment.py new file mode 100644 index 00000000..03497395 --- /dev/null +++ b/src/gcore/types/cloud/users/role_assignment.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["RoleAssignment"] + + +class RoleAssignment(BaseModel): + id: int + """Assignment ID""" + + assigned_by: Optional[int] = None + + client_id: int + """Client ID""" + + created_at: datetime + """Created timestamp""" + + project_id: Optional[int] = None + """Project ID""" + + role: Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"] + """User role""" + + updated_at: Optional[datetime] = None + """Updated timestamp""" + + user_id: int + """User ID""" diff --git a/src/gcore/types/cloud/users/role_assignment_create_params.py b/src/gcore/types/cloud/users/role_assignment_create_params.py new file mode 100644 index 00000000..3799fac3 --- /dev/null +++ b/src/gcore/types/cloud/users/role_assignment_create_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RoleAssignmentCreateParams"] + + +class RoleAssignmentCreateParams(TypedDict, total=False): + role: Required[ + Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"] + ] + """User role""" + + user_id: Required[int] + """User ID""" + + client_id: Optional[int] + """Client ID. Required if `project_id` is specified""" + + project_id: Optional[int] + """Project ID""" diff --git a/src/gcore/types/cloud/users/role_assignment_list_params.py b/src/gcore/types/cloud/users/role_assignment_list_params.py new file mode 100644 index 00000000..524a0450 --- /dev/null +++ b/src/gcore/types/cloud/users/role_assignment_list_params.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["RoleAssignmentListParams"] + + +class RoleAssignmentListParams(TypedDict, total=False): + limit: int + """Limit the number of returned items. + + Falls back to default of 1000 if not specified. Limited by max limit value of + 1000 + """ + + offset: int + """Offset value is used to exclude the first set of records from the result""" + + project_id: int + """Project ID""" + + user_id: int + """User ID for filtering""" diff --git a/src/gcore/types/cloud/users/role_assignment_update_params.py b/src/gcore/types/cloud/users/role_assignment_update_params.py new file mode 100644 index 00000000..10b6dc82 --- /dev/null +++ b/src/gcore/types/cloud/users/role_assignment_update_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["RoleAssignmentUpdateParams"] + + +class RoleAssignmentUpdateParams(TypedDict, total=False): + role: Required[ + Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"] + ] + """User role""" + + user_id: Required[int] + """User ID""" + + client_id: Optional[int] + """Client ID. Required if `project_id` is specified""" + + project_id: Optional[int] + """Project ID""" diff --git a/src/gcore/types/cloud/users/role_assignment_updated_deleted.py b/src/gcore/types/cloud/users/role_assignment_updated_deleted.py new file mode 100644 index 00000000..8c38f1c5 --- /dev/null +++ b/src/gcore/types/cloud/users/role_assignment_updated_deleted.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["RoleAssignmentUpdatedDeleted"] + + +class RoleAssignmentUpdatedDeleted(BaseModel): + assignment_id: int + """Assignment ID""" diff --git a/src/gcore/types/cloud/volume.py b/src/gcore/types/cloud/volume.py new file mode 100644 index 00000000..1ea6ff59 --- /dev/null +++ b/src/gcore/types/cloud/volume.py @@ -0,0 +1,143 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .tag import Tag +from ..._models import BaseModel + +__all__ = ["Volume", "Attachment", "LimiterStats"] + + +class Attachment(BaseModel): + attachment_id: str + """The unique identifier of the attachment object.""" + + volume_id: str + """The unique identifier of the attached volume.""" + + attached_at: Optional[datetime] = None + """The date and time when the attachment was created.""" + + device: Optional[str] = None + """The block device name inside the guest instance.""" + + flavor_id: Optional[str] = None + """The flavor ID of the instance.""" + + instance_name: Optional[str] = None + """The name of the instance if attached and the server name is known.""" + + server_id: Optional[str] = None + """The unique identifier of the instance.""" + + +class LimiterStats(BaseModel): + """Schema representing the Quality of Service (QoS) parameters for a volume.""" + + iops_base_limit: int + """The sustained IOPS (Input/Output Operations Per Second) limit.""" + + iops_burst_limit: int + """The burst IOPS limit.""" + + m_bps_base_limit: int = FieldInfo(alias="MBps_base_limit") + """The sustained bandwidth limit in megabytes per second (MBps).""" + + m_bps_burst_limit: int = FieldInfo(alias="MBps_burst_limit") + """The burst bandwidth limit in megabytes per second (MBps).""" + + +class Volume(BaseModel): + id: str + """The unique identifier of the volume.""" + + bootable: bool + """Indicates whether the volume is bootable.""" + + created_at: datetime + """The date and time when the volume was created.""" + + is_root_volume: bool + """Indicates whether this is a root volume.""" + + name: str + """The name of the volume.""" + + project_id: int + """Project ID.""" + + region: str + """The region where the volume is located.""" + + region_id: int + """The identifier of the region.""" + + size: int + """The size of the volume in gibibytes (GiB).""" + + status: Literal[ + "attaching", + "available", + "awaiting-transfer", + "backing-up", + "creating", + "deleting", + "detaching", + "downloading", + "error", + "error_backing-up", + "error_deleting", + "error_extending", + "error_restoring", + "extending", + "in-use", + "maintenance", + "reserved", + "restoring-backup", + "retyping", + "reverting", + "uploading", + ] + """The current status of the volume.""" + + tags: List[Tag] + """List of key-value tags associated with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Some + tags are read-only and cannot be modified by the user. Tags are also integrated + with cost reports, allowing cost data to be filtered based on tag keys or + values. + """ + + volume_type: str + """The type of volume storage.""" + + attachments: Optional[List[Attachment]] = None + """List of attachments associated with the volume.""" + + creator_task_id: Optional[str] = None + """The ID of the task that created this volume.""" + + limiter_stats: Optional[LimiterStats] = None + """Schema representing the Quality of Service (QoS) parameters for a volume.""" + + snapshot_ids: Optional[List[str]] = None + """List of snapshot IDs associated with this volume.""" + + task_id: Optional[str] = None + """The UUID of the active task that currently holds a lock on the resource. + + This lock prevents concurrent modifications to ensure consistency. If `null`, + the resource is not locked. + """ + + updated_at: Optional[datetime] = None + """The date and time when the volume was last updated.""" + + volume_image_metadata: Optional[Dict[str, str]] = None + """Image metadata for volumes created from an image.""" diff --git a/src/gcore/types/cloud/volume_attach_to_instance_params.py b/src/gcore/types/cloud/volume_attach_to_instance_params.py new file mode 100644 index 00000000..9b735a1a --- /dev/null +++ b/src/gcore/types/cloud/volume_attach_to_instance_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["VolumeAttachToInstanceParams"] + + +class VolumeAttachToInstanceParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + instance_id: Required[str] + """Instance ID.""" + + attachment_tag: str + """Block device attachment tag (not exposed in the normal tags).""" diff --git a/src/gcore/types/cloud/volume_change_type_params.py b/src/gcore/types/cloud/volume_change_type_params.py new file mode 100644 index 00000000..910cc5f5 --- /dev/null +++ b/src/gcore/types/cloud/volume_change_type_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["VolumeChangeTypeParams"] + + +class VolumeChangeTypeParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + volume_type: Required[Literal["ssd_hiiops", "standard"]] + """New volume type name""" diff --git a/src/gcore/types/cloud/volume_create_params.py b/src/gcore/types/cloud/volume_create_params.py new file mode 100644 index 00000000..2e2dd5a7 --- /dev/null +++ b/src/gcore/types/cloud/volume_create_params.py @@ -0,0 +1,176 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .tag_update_map_param import TagUpdateMapParam + +__all__ = [ + "VolumeCreateParams", + "CreateVolumeFromImageSerializer", + "CreateVolumeFromSnapshotSerializer", + "CreateNewVolumeSerializer", +] + + +class CreateVolumeFromImageSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + image_id: Required[str] + """Image ID""" + + name: Required[str] + """Volume name""" + + size: Required[int] + """Volume size in GiB""" + + source: Required[Literal["image"]] + """Volume source type""" + + attachment_tag: str + """Block device attachment tag (not exposed in the user tags). + + Only used in conjunction with `instance_id_to_attach_to` + """ + + instance_id_to_attach_to: str + """`instance_id` to attach newly-created volume to""" + + lifecycle_policy_ids: Iterable[int] + """ + List of lifecycle policy IDs (snapshot creation schedules) to associate with the + volume + """ + + tags: TagUpdateMapParam + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] + """Volume type. + + Defaults to `standard`. If not specified for source `snapshot`, volume type will + be derived from the snapshot volume. + """ + + +class CreateVolumeFromSnapshotSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: Required[str] + """Volume name""" + + snapshot_id: Required[str] + """Snapshot ID""" + + source: Required[Literal["snapshot"]] + """Volume source type""" + + attachment_tag: str + """Block device attachment tag (not exposed in the user tags). + + Only used in conjunction with `instance_id_to_attach_to` + """ + + instance_id_to_attach_to: str + """`instance_id` to attach newly-created volume to""" + + lifecycle_policy_ids: Iterable[int] + """ + List of lifecycle policy IDs (snapshot creation schedules) to associate with the + volume + """ + + size: int + """Volume size in GiB. + + If specified, value must be equal to respective snapshot size + """ + + tags: TagUpdateMapParam + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] + """Volume type. + + Defaults to `standard`. If not specified for source `snapshot`, volume type will + be derived from the snapshot volume. + """ + + +class CreateNewVolumeSerializer(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: Required[str] + """Volume name""" + + size: Required[int] + """Volume size in GiB""" + + source: Required[Literal["new-volume"]] + """Volume source type""" + + attachment_tag: str + """Block device attachment tag (not exposed in the user tags). + + Only used in conjunction with `instance_id_to_attach_to` + """ + + instance_id_to_attach_to: str + """`instance_id` to attach newly-created volume to""" + + lifecycle_policy_ids: Iterable[int] + """ + List of lifecycle policy IDs (snapshot creation schedules) to associate with the + volume + """ + + tags: TagUpdateMapParam + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ + + type_name: Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"] + """Volume type. + + Defaults to `standard`. If not specified for source `snapshot`, volume type will + be derived from the snapshot volume. + """ + + +VolumeCreateParams: TypeAlias = Union[ + CreateVolumeFromImageSerializer, CreateVolumeFromSnapshotSerializer, CreateNewVolumeSerializer +] diff --git a/src/gcore/types/cloud/volume_delete_params.py b/src/gcore/types/cloud/volume_delete_params.py new file mode 100644 index 00000000..a435163e --- /dev/null +++ b/src/gcore/types/cloud/volume_delete_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["VolumeDeleteParams"] + + +class VolumeDeleteParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + snapshots: str + """Comma separated list of snapshot IDs to be deleted with the volume.""" diff --git a/src/gcore/types/cloud/volume_detach_from_instance_params.py b/src/gcore/types/cloud/volume_detach_from_instance_params.py new file mode 100644 index 00000000..0332d605 --- /dev/null +++ b/src/gcore/types/cloud/volume_detach_from_instance_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["VolumeDetachFromInstanceParams"] + + +class VolumeDetachFromInstanceParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + instance_id: Required[str] + """Instance ID""" diff --git a/src/gcore/types/cloud/volume_list_params.py b/src/gcore/types/cloud/volume_list_params.py new file mode 100644 index 00000000..11fac11f --- /dev/null +++ b/src/gcore/types/cloud/volume_list_params.py @@ -0,0 +1,53 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["VolumeListParams"] + + +class VolumeListParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + bootable: bool + """Filter by bootable field""" + + cluster_id: str + """Filter volumes by k8s cluster ID""" + + has_attachments: bool + """Filter by the presence of attachments""" + + id_part: str + """Filter the volume list result by the ID part of the volume""" + + instance_id: str + """Filter volumes by instance ID""" + + limit: int + """Optional. Limit the number of returned items""" + + name_part: str + """ + Filter volumes by `name_part` inclusion in volume name.Any substring can be used + and volumes will be returned with names containing the substring. + """ + + offset: int + """Optional. + + Offset value is used to exclude the first set of records from the result + """ + + tag_key: SequenceNotStr[str] + """Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2""" + + tag_key_value: str + """Optional. Filter by tag key-value pairs.""" diff --git a/src/gcore/types/cloud/volume_resize_params.py b/src/gcore/types/cloud/volume_resize_params.py new file mode 100644 index 00000000..34091297 --- /dev/null +++ b/src/gcore/types/cloud/volume_resize_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["VolumeResizeParams"] + + +class VolumeResizeParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + size: Required[int] + """New volume size in GiB""" diff --git a/src/gcore/types/cloud/volume_snapshot_create_params.py b/src/gcore/types/cloud/volume_snapshot_create_params.py new file mode 100644 index 00000000..8d77c011 --- /dev/null +++ b/src/gcore/types/cloud/volume_snapshot_create_params.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["VolumeSnapshotCreateParams"] + + +class VolumeSnapshotCreateParams(TypedDict, total=False): + project_id: int + + region_id: int + + name: Required[str] + """Snapshot name""" + + volume_id: Required[str] + """Volume ID to make snapshot of""" + + description: str + """Snapshot description""" + + tags: object + """Key-value tags to associate with the resource. + + A tag is a key-value pair that can be associated with a resource, enabling + efficient filtering and grouping for better organization and management. Both + tag keys and values have a maximum length of 255 characters. Some tags are + read-only and cannot be modified by the user. Tags are also integrated with cost + reports, allowing cost data to be filtered based on tag keys or values. + """ diff --git a/src/gcore/types/cloud/volume_snapshot_update_params.py b/src/gcore/types/cloud/volume_snapshot_update_params.py new file mode 100644 index 00000000..7ac318f9 --- /dev/null +++ b/src/gcore/types/cloud/volume_snapshot_update_params.py @@ -0,0 +1,49 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +from .tag_update_map_param import TagUpdateMapParam + +__all__ = ["VolumeSnapshotUpdateParams"] + + +class VolumeSnapshotUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: str + """Display name for the snapshot (3-63 chars). + + Used in customer portal and API. Does not affect snapshot data. + """ + + tags: Optional[TagUpdateMapParam] + """Update key-value tags using JSON Merge Patch semantics (RFC 7386). + + Provide key-value pairs to add or update tags. Set tag values to `null` to + remove tags. Unspecified tags remain unchanged. Read-only tags are always + preserved and cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + """ diff --git a/src/gcore/types/cloud/volume_update_params.py b/src/gcore/types/cloud/volume_update_params.py new file mode 100644 index 00000000..a81d36f1 --- /dev/null +++ b/src/gcore/types/cloud/volume_update_params.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +from .tag_update_map_param import TagUpdateMapParam + +__all__ = ["VolumeUpdateParams"] + + +class VolumeUpdateParams(TypedDict, total=False): + project_id: int + """Project ID""" + + region_id: int + """Region ID""" + + name: str + """Name""" + + tags: Optional[TagUpdateMapParam] + """Update key-value tags using JSON Merge Patch semantics (RFC 7386). + + Provide key-value pairs to add or update tags. Set tag values to `null` to + remove tags. Unspecified tags remain unchanged. Read-only tags are always + preserved and cannot be modified. + + **Examples:** + + - **Add/update tags:** + `{'tags': {'environment': 'production', 'team': 'backend'}}` adds new tags or + updates existing ones. + - **Delete tags:** `{'tags': {'old_tag': null}}` removes specific tags. + - **Remove all tags:** `{'tags': null}` removes all user-managed tags (read-only + tags are preserved). + - **Partial update:** `{'tags': {'environment': 'staging'}}` only updates + specified tags. + - **Mixed operations:** + `{'tags': {'environment': 'production', 'cost_center': 'engineering', 'deprecated_tag': null}}` + adds/updates 'environment' and 'cost_center' while removing 'deprecated_tag', + preserving other existing tags. + - **Replace all:** first delete existing tags with null values, then add new + ones in the same request. + """ diff --git a/src/gcore/types/dns/__init__.py b/src/gcore/types/dns/__init__.py new file mode 100644 index 00000000..c42fa39f --- /dev/null +++ b/src/gcore/types/dns/__init__.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .dns_label_name import DNSLabelName as DNSLabelName +from .dns_name_server import DNSNameServer as DNSNameServer +from .zone_list_params import ZoneListParams as ZoneListParams +from .dns_lookup_params import DNSLookupParams as DNSLookupParams +from .dns_mapping_entry import DNSMappingEntry as DNSMappingEntry +from .zone_get_response import ZoneGetResponse as ZoneGetResponse +from .metric_list_params import MetricListParams as MetricListParams +from .zone_create_params import ZoneCreateParams as ZoneCreateParams +from .zone_import_params import ZoneImportParams as ZoneImportParams +from .zone_list_response import ZoneListResponse as ZoneListResponse +from .dns_lookup_response import DNSLookupResponse as DNSLookupResponse +from .dns_network_mapping import DNSNetworkMapping as DNSNetworkMapping +from .zone_replace_params import ZoneReplaceParams as ZoneReplaceParams +from .metric_list_response import MetricListResponse as MetricListResponse +from .picker_list_response import PickerListResponse as PickerListResponse +from .zone_create_response import ZoneCreateResponse as ZoneCreateResponse +from .zone_export_response import ZoneExportResponse as ZoneExportResponse +from .zone_import_response import ZoneImportResponse as ZoneImportResponse +from .location_list_response import LocationListResponse as LocationListResponse +from .dns_mapping_entry_param import DNSMappingEntryParam as DNSMappingEntryParam +from .dns_location_translations import DNSLocationTranslations as DNSLocationTranslations +from .zone_get_statistics_params import ZoneGetStatisticsParams as ZoneGetStatisticsParams +from .network_mapping_list_params import NetworkMappingListParams as NetworkMappingListParams +from .zone_get_statistics_response import ZoneGetStatisticsResponse as ZoneGetStatisticsResponse +from .network_mapping_create_params import NetworkMappingCreateParams as NetworkMappingCreateParams +from .network_mapping_list_response import NetworkMappingListResponse as NetworkMappingListResponse +from .location_list_regions_response import LocationListRegionsResponse as LocationListRegionsResponse +from .network_mapping_replace_params import NetworkMappingReplaceParams as NetworkMappingReplaceParams +from .network_mapping_create_response import NetworkMappingCreateResponse as NetworkMappingCreateResponse +from .network_mapping_import_response import NetworkMappingImportResponse as NetworkMappingImportResponse +from .location_list_countries_response import LocationListCountriesResponse as LocationListCountriesResponse +from .dns_get_account_overview_response import DNSGetAccountOverviewResponse as DNSGetAccountOverviewResponse +from .location_list_continents_response import LocationListContinentsResponse as LocationListContinentsResponse +from .zone_check_delegation_status_response import ( + ZoneCheckDelegationStatusResponse as ZoneCheckDelegationStatusResponse, +) diff --git a/src/gcore/types/dns/dns_get_account_overview_response.py b/src/gcore/types/dns/dns_get_account_overview_response.py new file mode 100644 index 00000000..6f91a78e --- /dev/null +++ b/src/gcore/types/dns/dns_get_account_overview_response.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["DNSGetAccountOverviewResponse", "Info"] + + +class Info(BaseModel): + contact: Optional[str] = None + + name_server_1: Optional[str] = None + + name_server_2: Optional[str] = None + + +class DNSGetAccountOverviewResponse(BaseModel): + info: Optional[Info] = FieldInfo(alias="Info", default=None) diff --git a/src/gcore/types/dns/dns_label_name.py b/src/gcore/types/dns/dns_label_name.py new file mode 100644 index 00000000..39d3d6be --- /dev/null +++ b/src/gcore/types/dns/dns_label_name.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["DNSLabelName"] + + +class DNSLabelName(BaseModel): + label: Optional[str] = None + + name: Optional[str] = None diff --git a/src/gcore/types/dns/dns_location_translations.py b/src/gcore/types/dns/dns_location_translations.py new file mode 100644 index 00000000..39548849 --- /dev/null +++ b/src/gcore/types/dns/dns_location_translations.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional + +from ..._models import BaseModel + +__all__ = ["DNSLocationTranslations"] + + +class DNSLocationTranslations(BaseModel): + names: Optional[Dict[str, str]] = None diff --git a/src/gcore/types/dns/dns_lookup_params.py b/src/gcore/types/dns/dns_lookup_params.py new file mode 100644 index 00000000..69e0e8ad --- /dev/null +++ b/src/gcore/types/dns/dns_lookup_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["DNSLookupParams"] + + +class DNSLookupParams(TypedDict, total=False): + name: str + """Domain name""" + + request_server: Literal["authoritative_dns", "google", "cloudflare", "open_dns", "quad9", "gcore"] + """Server that will be used as resolver""" diff --git a/src/gcore/types/dns/dns_lookup_response.py b/src/gcore/types/dns/dns_lookup_response.py new file mode 100644 index 00000000..f6c13c57 --- /dev/null +++ b/src/gcore/types/dns/dns_lookup_response.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["DNSLookupResponse", "DNSLookupResponseItem"] + + +class DNSLookupResponseItem(BaseModel): + content: Optional[List[str]] = None + + name: Optional[str] = None + + ttl: Optional[int] = None + + type: Optional[str] = None + + +DNSLookupResponse: TypeAlias = List[DNSLookupResponseItem] diff --git a/src/gcore/types/dns/dns_mapping_entry.py b/src/gcore/types/dns/dns_mapping_entry.py new file mode 100644 index 00000000..5d8db17c --- /dev/null +++ b/src/gcore/types/dns/dns_mapping_entry.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["DNSMappingEntry"] + + +class DNSMappingEntry(BaseModel): + cidr4: Optional[List[str]] = None + + cidr6: Optional[List[str]] = None + + tags: Optional[List[str]] = None diff --git a/src/gcore/types/dns/dns_mapping_entry_param.py b/src/gcore/types/dns/dns_mapping_entry_param.py new file mode 100644 index 00000000..d6504b98 --- /dev/null +++ b/src/gcore/types/dns/dns_mapping_entry_param.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["DNSMappingEntryParam"] + + +class DNSMappingEntryParam(TypedDict, total=False): + cidr4: SequenceNotStr[str] + + cidr6: SequenceNotStr[str] + + tags: SequenceNotStr[str] diff --git a/src/gcore/types/dns/dns_name_server.py b/src/gcore/types/dns/dns_name_server.py new file mode 100644 index 00000000..e865a7ba --- /dev/null +++ b/src/gcore/types/dns/dns_name_server.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["DNSNameServer"] + + +class DNSNameServer(BaseModel): + """NameServer""" + + ipv4_addresses: Optional[List[str]] = FieldInfo(alias="ipv4Addresses", default=None) + + ipv6_addresses: Optional[List[str]] = FieldInfo(alias="ipv6Addresses", default=None) + + name: Optional[str] = None diff --git a/src/gcore/types/dns/dns_network_mapping.py b/src/gcore/types/dns/dns_network_mapping.py new file mode 100644 index 00000000..d4daac0c --- /dev/null +++ b/src/gcore/types/dns/dns_network_mapping.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .dns_mapping_entry import DNSMappingEntry + +__all__ = ["DNSNetworkMapping"] + + +class DNSNetworkMapping(BaseModel): + id: Optional[int] = None + + mapping: Optional[List[DNSMappingEntry]] = None + + name: Optional[str] = None diff --git a/src/gcore/types/dns/location_list_continents_response.py b/src/gcore/types/dns/location_list_continents_response.py new file mode 100644 index 00000000..09e5397e --- /dev/null +++ b/src/gcore/types/dns/location_list_continents_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict +from typing_extensions import TypeAlias + +from .dns_location_translations import DNSLocationTranslations + +__all__ = ["LocationListContinentsResponse"] + +LocationListContinentsResponse: TypeAlias = Dict[str, DNSLocationTranslations] diff --git a/src/gcore/types/dns/location_list_countries_response.py b/src/gcore/types/dns/location_list_countries_response.py new file mode 100644 index 00000000..4ea48d98 --- /dev/null +++ b/src/gcore/types/dns/location_list_countries_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict +from typing_extensions import TypeAlias + +from .dns_location_translations import DNSLocationTranslations + +__all__ = ["LocationListCountriesResponse"] + +LocationListCountriesResponse: TypeAlias = Dict[str, DNSLocationTranslations] diff --git a/src/gcore/types/dns/location_list_regions_response.py b/src/gcore/types/dns/location_list_regions_response.py new file mode 100644 index 00000000..b6f68a7b --- /dev/null +++ b/src/gcore/types/dns/location_list_regions_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict +from typing_extensions import TypeAlias + +from .dns_location_translations import DNSLocationTranslations + +__all__ = ["LocationListRegionsResponse"] + +LocationListRegionsResponse: TypeAlias = Dict[str, DNSLocationTranslations] diff --git a/src/gcore/types/dns/location_list_response.py b/src/gcore/types/dns/location_list_response.py new file mode 100644 index 00000000..d76f5f7e --- /dev/null +++ b/src/gcore/types/dns/location_list_response.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional + +from ..._models import BaseModel +from .dns_location_translations import DNSLocationTranslations + +__all__ = ["LocationListResponse"] + + +class LocationListResponse(BaseModel): + continents: Optional[Dict[str, DNSLocationTranslations]] = None + + countries: Optional[Dict[str, DNSLocationTranslations]] = None + + regions: Optional[Dict[str, DNSLocationTranslations]] = None diff --git a/src/gcore/types/dns/metric_list_params.py b/src/gcore/types/dns/metric_list_params.py new file mode 100644 index 00000000..46e9a926 --- /dev/null +++ b/src/gcore/types/dns/metric_list_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["MetricListParams"] + + +class MetricListParams(TypedDict, total=False): + client_ids: Iterable[int] + """ + Admin and technical user can specify `client_id` to get metrics for particular + client. Ignored for client + """ + + zone_names: SequenceNotStr[str] + """ + Admin and technical user can specify `monitor_id` to get metrics for particular + zone. Ignored for client + """ diff --git a/src/gcore/types/dns/metric_list_response.py b/src/gcore/types/dns/metric_list_response.py new file mode 100644 index 00000000..54fa0de0 --- /dev/null +++ b/src/gcore/types/dns/metric_list_response.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import TypeAlias + +__all__ = ["MetricListResponse"] + +MetricListResponse: TypeAlias = str diff --git a/src/gcore/types/dns/network_mapping_create_params.py b/src/gcore/types/dns/network_mapping_create_params.py new file mode 100644 index 00000000..d670478a --- /dev/null +++ b/src/gcore/types/dns/network_mapping_create_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import TypedDict + +from .dns_mapping_entry_param import DNSMappingEntryParam + +__all__ = ["NetworkMappingCreateParams"] + + +class NetworkMappingCreateParams(TypedDict, total=False): + mapping: Iterable[DNSMappingEntryParam] + + name: str diff --git a/src/gcore/types/dns/network_mapping_create_response.py b/src/gcore/types/dns/network_mapping_create_response.py new file mode 100644 index 00000000..7f2046aa --- /dev/null +++ b/src/gcore/types/dns/network_mapping_create_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["NetworkMappingCreateResponse"] + + +class NetworkMappingCreateResponse(BaseModel): + id: Optional[int] = None diff --git a/src/gcore/types/dns/network_mapping_import_response.py b/src/gcore/types/dns/network_mapping_import_response.py new file mode 100644 index 00000000..55e94e10 --- /dev/null +++ b/src/gcore/types/dns/network_mapping_import_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["NetworkMappingImportResponse"] + + +class NetworkMappingImportResponse(BaseModel): + success: Optional[bool] = None diff --git a/src/gcore/types/dns/network_mapping_list_params.py b/src/gcore/types/dns/network_mapping_list_params.py new file mode 100644 index 00000000..913e70fe --- /dev/null +++ b/src/gcore/types/dns/network_mapping_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["NetworkMappingListParams"] + + +class NetworkMappingListParams(TypedDict, total=False): + limit: int + """Max number of records in response""" + + offset: int + """Amount of records to skip before beginning to write in response.""" + + order_by: str + """Field name to sort by""" + + order_direction: Literal["asc", "desc"] + """Ascending or descending order""" diff --git a/src/gcore/types/dns/network_mapping_list_response.py b/src/gcore/types/dns/network_mapping_list_response.py new file mode 100644 index 00000000..fba55a5a --- /dev/null +++ b/src/gcore/types/dns/network_mapping_list_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .dns_network_mapping import DNSNetworkMapping + +__all__ = ["NetworkMappingListResponse"] + + +class NetworkMappingListResponse(BaseModel): + network_mappings: Optional[List[DNSNetworkMapping]] = None + + total_amount: Optional[int] = None diff --git a/src/gcore/types/dns/network_mapping_replace_params.py b/src/gcore/types/dns/network_mapping_replace_params.py new file mode 100644 index 00000000..7e7d7b2e --- /dev/null +++ b/src/gcore/types/dns/network_mapping_replace_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import TypedDict + +from .dns_mapping_entry_param import DNSMappingEntryParam + +__all__ = ["NetworkMappingReplaceParams"] + + +class NetworkMappingReplaceParams(TypedDict, total=False): + mapping: Iterable[DNSMappingEntryParam] + + name: str diff --git a/src/gcore/types/dns/picker_list_response.py b/src/gcore/types/dns/picker_list_response.py new file mode 100644 index 00000000..99a3ab8d --- /dev/null +++ b/src/gcore/types/dns/picker_list_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .dns_label_name import DNSLabelName + +__all__ = ["PickerListResponse"] + +PickerListResponse: TypeAlias = List[DNSLabelName] diff --git a/src/gcore/types/dns/pickers/__init__.py b/src/gcore/types/dns/pickers/__init__.py new file mode 100644 index 00000000..1041654d --- /dev/null +++ b/src/gcore/types/dns/pickers/__init__.py @@ -0,0 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .preset_list_response import PresetListResponse as PresetListResponse diff --git a/src/gcore/types/dns/pickers/preset_list_response.py b/src/gcore/types/dns/pickers/preset_list_response.py new file mode 100644 index 00000000..47ea0e01 --- /dev/null +++ b/src/gcore/types/dns/pickers/preset_list_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List +from typing_extensions import TypeAlias + +from ..dns_label_name import DNSLabelName + +__all__ = ["PresetListResponse"] + +PresetListResponse: TypeAlias = Dict[str, List[DNSLabelName]] diff --git a/src/gcore/types/dns/zone_check_delegation_status_response.py b/src/gcore/types/dns/zone_check_delegation_status_response.py new file mode 100644 index 00000000..ae89139a --- /dev/null +++ b/src/gcore/types/dns/zone_check_delegation_status_response.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .dns_name_server import DNSNameServer + +__all__ = ["ZoneCheckDelegationStatusResponse"] + + +class ZoneCheckDelegationStatusResponse(BaseModel): + authoritative_name_servers: Optional[List[DNSNameServer]] = None + + gcore_authorized_count: Optional[int] = None + + is_whitelabel_delegation: Optional[bool] = None + + non_gcore_authorized_count: Optional[int] = None + + zone_exists: Optional[bool] = None diff --git a/src/gcore/types/dns/zone_create_params.py b/src/gcore/types/dns/zone_create_params.py new file mode 100644 index 00000000..893ee168 --- /dev/null +++ b/src/gcore/types/dns/zone_create_params.py @@ -0,0 +1,59 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict +from typing_extensions import Required, TypedDict + +__all__ = ["ZoneCreateParams"] + + +class ZoneCreateParams(TypedDict, total=False): + name: Required[str] + """name of DNS zone""" + + contact: str + """email address of the administrator responsible for this zone""" + + enabled: bool + """If a zone is disabled, then its records will not be resolved on dns servers""" + + expiry: int + """ + number of seconds after which secondary name servers should stop answering + request for this zone + """ + + meta: Dict[str, object] + """ + arbitrarily data of zone in json format you can specify `webhook` url and + `webhook_method` here webhook will get a map with three arrays: for created, + updated and deleted rrsets `webhook_method` can be omitted, POST will be used by + default + """ + + nx_ttl: int + """Time To Live of cache""" + + primary_server: str + """primary master name server for zone""" + + refresh: int + """ + number of seconds after which secondary name servers should query the master for + the SOA record, to detect zone changes. + """ + + retry: int + """ + number of seconds after which secondary name servers should retry to request the + serial number + """ + + serial: int + """ + Serial number for this zone or Timestamp of zone modification moment. If a + secondary name server slaved to this one observes an increase in this number, + the slave will assume that the zone has been updated and initiate a zone + transfer. + """ diff --git a/src/gcore/types/dns/zone_create_response.py b/src/gcore/types/dns/zone_create_response.py new file mode 100644 index 00000000..24191c26 --- /dev/null +++ b/src/gcore/types/dns/zone_create_response.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["ZoneCreateResponse"] + + +class ZoneCreateResponse(BaseModel): + id: Optional[int] = None + + warnings: Optional[List[str]] = None diff --git a/src/gcore/types/dns/zone_export_response.py b/src/gcore/types/dns/zone_export_response.py new file mode 100644 index 00000000..89ec6d3e --- /dev/null +++ b/src/gcore/types/dns/zone_export_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["ZoneExportResponse"] + + +class ZoneExportResponse(BaseModel): + raw_zone: Optional[str] = None diff --git a/src/gcore/types/dns/zone_get_response.py b/src/gcore/types/dns/zone_get_response.py new file mode 100644 index 00000000..b984fa7a --- /dev/null +++ b/src/gcore/types/dns/zone_get_response.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ..._models import BaseModel + +__all__ = ["ZoneGetResponse", "Record", "RrsetsAmount", "RrsetsAmountDynamic"] + + +class Record(BaseModel): + """Record - readonly short version of rrset""" + + name: Optional[str] = None + + short_answers: Optional[List[str]] = None + + ttl: Optional[int] = None + + type: Optional[str] = None + + +class RrsetsAmountDynamic(BaseModel): + """Amount of dynamic RRsets in zone""" + + healthcheck: Optional[int] = None + """Amount of RRsets with enabled healthchecks""" + + total: Optional[int] = None + """Total amount of dynamic RRsets in zone""" + + +class RrsetsAmount(BaseModel): + dynamic: Optional[RrsetsAmountDynamic] = None + """Amount of dynamic RRsets in zone""" + + static: Optional[int] = None + """Amount of static RRsets in zone""" + + total: Optional[int] = None + """Total amount of RRsets in zone""" + + +class ZoneGetResponse(BaseModel): + """Complete zone info with all records included""" + + id: Optional[int] = None + """ + ID of zone. This field usually is omitted in response and available only in case + of getting deleted zones by admin. + """ + + contact: Optional[str] = None + """email address of the administrator responsible for this zone""" + + dnssec_enabled: Optional[bool] = None + """ + describe dnssec status true means dnssec is enabled for the zone false means + dnssec is disabled for the zone + """ + + enabled: Optional[bool] = None + + expiry: Optional[int] = None + """ + number of seconds after which secondary name servers should stop answering + request for this zone + """ + + meta: Optional[Dict[str, object]] = None + """arbitrarily data of zone in json format""" + + name: Optional[str] = None + """name of DNS zone""" + + nx_ttl: Optional[int] = None + """Time To Live of cache""" + + primary_server: Optional[str] = None + """primary master name server for zone""" + + records: Optional[List[Record]] = None + + refresh: Optional[int] = None + """ + number of seconds after which secondary name servers should query the master for + the SOA record, to detect zone changes. + """ + + retry: Optional[int] = None + """ + number of seconds after which secondary name servers should retry to request the + serial number + """ + + rrsets_amount: Optional[RrsetsAmount] = None + + serial: Optional[int] = None + """ + Serial number for this zone or Timestamp of zone modification moment. If a + secondary name server slaved to this one observes an increase in this number, + the slave will assume that the zone has been updated and initiate a zone + transfer. + """ + + status: Optional[str] = None diff --git a/src/gcore/types/dns/zone_get_statistics_params.py b/src/gcore/types/dns/zone_get_statistics_params.py new file mode 100644 index 00000000..2db7a140 --- /dev/null +++ b/src/gcore/types/dns/zone_get_statistics_params.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["ZoneGetStatisticsParams"] + + +class ZoneGetStatisticsParams(TypedDict, total=False): + from_: Annotated[int, PropertyInfo(alias="from")] + """Beginning of the requested time period (Unix Timestamp, UTC.) + + In a query string: &from=1709068637 + """ + + granularity: str + """ + Granularity parameter string is a sequence of decimal numbers, each with + optional fraction and a unit suffix, such as "300ms", "1.5h" or "2h45m". + + Valid time units are "s", "m", "h". + """ + + record_type: str + """DNS record type. + + Possible values: + + - A + - AAAA + - NS + - CNAME + - MX + - TXT + - SVCB + - HTTPS + """ + + to: int + """End of the requested time period (Unix Timestamp, UTC.) + + In a query string: &to=1709673437 + """ diff --git a/src/gcore/types/dns/zone_get_statistics_response.py b/src/gcore/types/dns/zone_get_statistics_response.py new file mode 100644 index 00000000..9c992062 --- /dev/null +++ b/src/gcore/types/dns/zone_get_statistics_response.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["ZoneGetStatisticsResponse"] + + +class ZoneGetStatisticsResponse(BaseModel): + """StatisticsZoneResponse""" + + requests: Optional[object] = None + """ + Requests amount (values) for particular zone fractionated by time intervals + (keys). + + Example of response: + `{ "requests": { "1598608080000": 14716, "1598608140000": 51167, "1598608200000": 53432, "1598611020000": 51050, "1598611080000": 52611, "1598611140000": 46884 } }` + """ + + total: Optional[int] = None + """Total - sum of all values""" diff --git a/src/gcore/types/dns/zone_import_params.py b/src/gcore/types/dns/zone_import_params.py new file mode 100644 index 00000000..5f189393 --- /dev/null +++ b/src/gcore/types/dns/zone_import_params.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ZoneImportParams"] + + +class ZoneImportParams(TypedDict, total=False): + body: object + """Read reads up to len(p) bytes into p. + + It returns the number of bytes read (0 <= n <= len(p)) and any error + encountered. Even if Read returns n < len(p), it may use all of p as scratch + space during the call. If some data is available but not len(p) bytes, Read + conventionally returns what is available instead of waiting for more. + + When Read encounters an error or end-of-file condition after successfully + reading n > 0 bytes, it returns the number of bytes read. It may return the + (non-nil) error from the same call or return the error (and n == 0) from a + subsequent call. An instance of this general case is that a Reader returning a + non-zero number of bytes at the end of the input stream may return either err == + EOF or err == nil. The next Read should return 0, EOF. + + Callers should always process the n > 0 bytes returned before considering the + error err. Doing so correctly handles I/O errors that happen after reading some + bytes and also both of the allowed EOF behaviors. + + If len(p) == 0, Read should always return n == 0. It may return a non-nil error + if some error condition is known, such as EOF. + + Implementations of Read are discouraged from returning a zero byte count with a + nil error, except when len(p) == 0. Callers should treat a return of 0 and nil + as indicating that nothing happened; in particular it does not indicate EOF. + + Implementations must not retain p. + """ diff --git a/src/gcore/types/dns/zone_import_response.py b/src/gcore/types/dns/zone_import_response.py new file mode 100644 index 00000000..75f07129 --- /dev/null +++ b/src/gcore/types/dns/zone_import_response.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional + +from ..._models import BaseModel + +__all__ = ["ZoneImportResponse", "Imported"] + + +class Imported(BaseModel): + """ImportedRRSets - import statistics""" + + qtype: Optional[int] = None + + resource_records: Optional[int] = None + + rrsets: Optional[int] = None + + skipped_resource_records: Optional[int] = None + + +class ZoneImportResponse(BaseModel): + imported: Optional[Imported] = None + """ImportedRRSets - import statistics""" + + success: Optional[bool] = None + + warnings: Optional[Dict[str, Dict[str, str]]] = None diff --git a/src/gcore/types/dns/zone_list_params.py b/src/gcore/types/dns/zone_list_params.py new file mode 100644 index 00000000..1bee33db --- /dev/null +++ b/src/gcore/types/dns/zone_list_params.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from datetime import datetime +from typing_extensions import Literal, Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = ["ZoneListParams"] + + +class ZoneListParams(TypedDict, total=False): + id: Iterable[int] + """to pass several ids `id=1&id=3&id=5...`""" + + case_sensitive: bool + + client_id: Iterable[int] + """to pass several `client_ids` `client_id=1&client_id=3&client_id=5...`""" + + dynamic: bool + """Zones with dynamic RRsets""" + + enabled: bool + + exact_match: bool + + healthcheck: bool + """Zones with RRsets that have healthchecks""" + + iam_reseller_id: Iterable[int] + + limit: int + """Max number of records in response""" + + name: SequenceNotStr[str] + """to pass several names `name=first&name=second...`""" + + offset: int + """Amount of records to skip before beginning to write in response.""" + + order_by: str + """Field name to sort by""" + + order_direction: Literal["asc", "desc"] + """Ascending or descending order""" + + reseller_id: Iterable[int] + + status: str + + updated_at_from: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + + updated_at_to: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] diff --git a/src/gcore/types/dns/zone_list_response.py b/src/gcore/types/dns/zone_list_response.py new file mode 100644 index 00000000..4b0a0277 --- /dev/null +++ b/src/gcore/types/dns/zone_list_response.py @@ -0,0 +1,113 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ..._models import BaseModel + +__all__ = ["ZoneListResponse", "Zone", "ZoneRecord", "ZoneRrsetsAmount", "ZoneRrsetsAmountDynamic"] + + +class ZoneRecord(BaseModel): + """Record - readonly short version of rrset""" + + name: Optional[str] = None + + short_answers: Optional[List[str]] = None + + ttl: Optional[int] = None + + type: Optional[str] = None + + +class ZoneRrsetsAmountDynamic(BaseModel): + """Amount of dynamic RRsets in zone""" + + healthcheck: Optional[int] = None + """Amount of RRsets with enabled healthchecks""" + + total: Optional[int] = None + """Total amount of dynamic RRsets in zone""" + + +class ZoneRrsetsAmount(BaseModel): + dynamic: Optional[ZoneRrsetsAmountDynamic] = None + """Amount of dynamic RRsets in zone""" + + static: Optional[int] = None + """Amount of static RRsets in zone""" + + total: Optional[int] = None + """Total amount of RRsets in zone""" + + +class Zone(BaseModel): + """OutputZone""" + + id: Optional[int] = None + """ + ID of zone. This field usually is omitted in response and available only in case + of getting deleted zones by admin. + """ + + client_id: Optional[int] = None + + contact: Optional[str] = None + """email address of the administrator responsible for this zone""" + + dnssec_enabled: Optional[bool] = None + """ + describe dnssec status true means dnssec is enabled for the zone false means + dnssec is disabled for the zone + """ + + enabled: Optional[bool] = None + + expiry: Optional[int] = None + """ + number of seconds after which secondary name servers should stop answering + request for this zone + """ + + meta: Optional[Dict[str, object]] = None + """arbitrarily data of zone in json format""" + + name: Optional[str] = None + """name of DNS zone""" + + nx_ttl: Optional[int] = None + """Time To Live of cache""" + + primary_server: Optional[str] = None + """primary master name server for zone""" + + records: Optional[List[ZoneRecord]] = None + + refresh: Optional[int] = None + """ + number of seconds after which secondary name servers should query the master for + the SOA record, to detect zone changes. + """ + + retry: Optional[int] = None + """ + number of seconds after which secondary name servers should retry to request the + serial number + """ + + rrsets_amount: Optional[ZoneRrsetsAmount] = None + + serial: Optional[int] = None + """ + Serial number for this zone or Timestamp of zone modification moment. If a + secondary name server slaved to this one observes an increase in this number, + the slave will assume that the zone has been updated and initiate a zone + transfer. + """ + + status: Optional[str] = None + + +class ZoneListResponse(BaseModel): + total_amount: Optional[int] = None + + zones: Optional[List[Zone]] = None diff --git a/src/gcore/types/dns/zone_replace_params.py b/src/gcore/types/dns/zone_replace_params.py new file mode 100644 index 00000000..43ab2045 --- /dev/null +++ b/src/gcore/types/dns/zone_replace_params.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["ZoneReplaceParams"] + + +class ZoneReplaceParams(TypedDict, total=False): + body_name: Required[Annotated[str, PropertyInfo(alias="name")]] + """name of DNS zone""" + + contact: str + """email address of the administrator responsible for this zone""" + + enabled: bool + """If a zone is disabled, then its records will not be resolved on dns servers""" + + expiry: int + """ + number of seconds after which secondary name servers should stop answering + request for this zone + """ + + meta: Dict[str, object] + """ + arbitrarily data of zone in json format you can specify `webhook` url and + `webhook_method` here webhook will get a map with three arrays: for created, + updated and deleted rrsets `webhook_method` can be omitted, POST will be used by + default + """ + + nx_ttl: int + """Time To Live of cache""" + + primary_server: str + """primary master name server for zone""" + + refresh: int + """ + number of seconds after which secondary name servers should query the master for + the SOA record, to detect zone changes. + """ + + retry: int + """ + number of seconds after which secondary name servers should retry to request the + serial number + """ + + serial: int + """ + Serial number for this zone or Timestamp of zone modification moment. If a + secondary name server slaved to this one observes an increase in this number, + the slave will assume that the zone has been updated and initiate a zone + transfer. + """ diff --git a/src/gcore/types/dns/zones/__init__.py b/src/gcore/types/dns/zones/__init__.py new file mode 100644 index 00000000..23fa909e --- /dev/null +++ b/src/gcore/types/dns/zones/__init__.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .dns_failover_log import DNSFailoverLog as DNSFailoverLog +from .dns_output_rrset import DNSOutputRrset as DNSOutputRrset +from .rrset_list_params import RrsetListParams as RrsetListParams +from .dnssec_get_response import DnssecGetResponse as DnssecGetResponse +from .rrset_create_params import RrsetCreateParams as RrsetCreateParams +from .rrset_list_response import RrsetListResponse as RrsetListResponse +from .dnssec_update_params import DnssecUpdateParams as DnssecUpdateParams +from .rrset_replace_params import RrsetReplaceParams as RrsetReplaceParams +from .dnssec_update_response import DnssecUpdateResponse as DnssecUpdateResponse +from .rrset_get_failover_logs_params import RrsetGetFailoverLogsParams as RrsetGetFailoverLogsParams +from .rrset_get_failover_logs_response import RrsetGetFailoverLogsResponse as RrsetGetFailoverLogsResponse diff --git a/src/gcore/types/dns/zones/dns_failover_log.py b/src/gcore/types/dns/zones/dns_failover_log.py new file mode 100644 index 00000000..2c37f385 --- /dev/null +++ b/src/gcore/types/dns/zones/dns_failover_log.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import TypeAlias + +from ...._models import BaseModel + +__all__ = ["DNSFailoverLog", "DNSFailoverLogItem"] + + +class DNSFailoverLogItem(BaseModel): + """FailoverLogEntry""" + + action: Optional[str] = None + + address: Optional[str] = None + + time: Optional[int] = None + + +DNSFailoverLog: TypeAlias = List[DNSFailoverLogItem] diff --git a/src/gcore/types/dns/zones/dns_output_rrset.py b/src/gcore/types/dns/zones/dns_output_rrset.py new file mode 100644 index 00000000..67b794d6 --- /dev/null +++ b/src/gcore/types/dns/zones/dns_output_rrset.py @@ -0,0 +1,127 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["DNSOutputRrset", "ResourceRecord", "Picker", "Warning"] + + +class ResourceRecord(BaseModel): + content: List[object] + """ + Content of resource record The exact length of the array depends on the type of + rrset, each individual record parameter must be a separate element of the array. + For example + + - SRV-record: `[100, 1, 5061, "example.com"]` + - CNAME-record: `[ "the.target.domain" ]` + - A-record: `[ "1.2.3.4", "5.6.7.8" ]` + - AAAA-record: `[ "2001:db8::1", "2001:db8::2" ]` + - MX-record: `[ "mail1.example.com", "mail2.example.com" ]` + - SVCB/HTTPS-record: + `[ 1, ".", ["alpn", "h3", "h2"], [ "port", 1443 ], [ "ipv4hint", "10.0.0.1" ], [ "ech", "AEn+DQBFKwAgACABWIHUGj4u+PIggYXcR5JF0gYk3dCRioBW8uJq9H4mKAAIAAEAAQABAANAEnB1YmxpYy50bHMtZWNoLmRldgAA" ] ]` + """ + + id: Optional[int] = None + + enabled: Optional[bool] = None + + meta: Optional[Dict[str, object]] = None + """ + Meta information for record Map with string key and any valid json as value, + with valid keys + + 1. `asn` (array of int) + 2. `continents` (array of string) + 3. `countries` (array of string) + 4. `latlong` (array of float64, latitude and longitude) + 5. `backup` (bool) + 6. `notes` (string) + 7. `weight` (float) + 8. `ip` (string) + 9. `default` (bool) + + Some keys are reserved for balancing, @see + https://api.gcore.com/dns/v2/info/meta + + This meta will be used to decide which resource record should pass through + filters from the filter set + """ + + +class Picker(BaseModel): + type: Literal[ + "geodns", "asn", "country", "continent", "region", "ip", "geodistance", "weighted_shuffle", "default", "first_n" + ] + """Filter type""" + + limit: Optional[int] = None + """ + Limits the number of records returned by the filter Can be a positive value for + a specific limit. Use zero or leave it blank to indicate no limits. + """ + + strict: Optional[bool] = None + """ + if strict=false, then the filter will return all records if no records match the + filter + """ + + +class Warning(BaseModel): + key: Optional[str] = None + + message: Optional[str] = None + + +class DNSOutputRrset(BaseModel): + name: str + + resource_records: List[ResourceRecord] + """List of resource record from rrset""" + + type: Literal["A", "AAAA", "NS", "CNAME", "MX", "TXT", "SRV", "SOA"] + """RRSet type""" + + filter_set_id: Optional[int] = None + + meta: Optional[Dict[str, object]] = None + """Meta information for rrset. + + Map with string key and any valid json as value, with valid keys + + 1. `failover` (object, beta feature, might be changed in the future) can have + fields 1.1. `protocol` (string, required, HTTP, TCP, UDP, ICMP) 1.2. `port` + (int, required, 1-65535) 1.3. `frequency` (int, required, in seconds 10-3600) + 1.4. `timeout` (int, required, in seconds 1-10), 1.5. `method` (string, only + for protocol=HTTP) 1.6. `command` (string, bytes to be sent only for + protocol=TCP/UDP) 1.7. `url` (string, only for protocol=HTTP) 1.8. `tls` + (bool, only for protocol=HTTP) 1.9. `regexp` (string regex to match, only for + non-ICMP) 1.10. `http_status_code` (int, only for protocol=HTTP) 1.11. `host` + (string, only for protocol=HTTP) + 2. `geodns_link` (string) - name of the geodns link to use, if previously set, + must re-send when updating or CDN integration will be removed for this RRSet + """ + + pickers: Optional[List[Picker]] = None + """Set of pickers""" + + ttl: Optional[int] = None + + updated_at: Optional[datetime] = None + """Timestamp marshals/unmarshals date and time as timestamp in json""" + + warning: Optional[str] = None + """ + Warning about some possible side effects without strictly disallowing operations + on rrset readonly Deprecated: use Warnings instead + """ + + warnings: Optional[List[Warning]] = None + """ + Warning about some possible side effects without strictly disallowing operations + on rrset readonly + """ diff --git a/src/gcore/types/dns/zones/dnssec_get_response.py b/src/gcore/types/dns/zones/dnssec_get_response.py new file mode 100644 index 00000000..b4220914 --- /dev/null +++ b/src/gcore/types/dns/zones/dnssec_get_response.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["DnssecGetResponse"] + + +class DnssecGetResponse(BaseModel): + algorithm: Optional[str] = None + """Specifies the algorithm used for the key.""" + + digest: Optional[str] = None + """Represents the hashed value of the DS record.""" + + digest_algorithm: Optional[str] = None + """Specifies the algorithm used to generate the digest.""" + + digest_type: Optional[str] = None + """Specifies the type of the digest algorithm used.""" + + ds: Optional[str] = None + """Represents the complete DS record.""" + + flags: Optional[int] = None + """Represents the flag for DNSSEC record.""" + + key_tag: Optional[int] = None + """Represents the identifier of the DNSKEY record.""" + + key_type: Optional[str] = None + """Specifies the type of the key used in the algorithm.""" + + public_key: Optional[str] = None + """Represents the public key used in the DS record.""" + + uuid: Optional[str] = None diff --git a/src/gcore/types/dns/zones/dnssec_update_params.py b/src/gcore/types/dns/zones/dnssec_update_params.py new file mode 100644 index 00000000..68249d14 --- /dev/null +++ b/src/gcore/types/dns/zones/dnssec_update_params.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["DnssecUpdateParams"] + + +class DnssecUpdateParams(TypedDict, total=False): + enabled: bool diff --git a/src/gcore/types/dns/zones/dnssec_update_response.py b/src/gcore/types/dns/zones/dnssec_update_response.py new file mode 100644 index 00000000..e552fd18 --- /dev/null +++ b/src/gcore/types/dns/zones/dnssec_update_response.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["DnssecUpdateResponse"] + + +class DnssecUpdateResponse(BaseModel): + algorithm: Optional[str] = None + """Specifies the algorithm used for the key.""" + + digest: Optional[str] = None + """Represents the hashed value of the DS record.""" + + digest_algorithm: Optional[str] = None + """Specifies the algorithm used to generate the digest.""" + + digest_type: Optional[str] = None + """Specifies the type of the digest algorithm used.""" + + ds: Optional[str] = None + """Represents the complete DS record.""" + + flags: Optional[int] = None + """Represents the flag for DNSSEC record.""" + + key_tag: Optional[int] = None + """Represents the identifier of the DNSKEY record.""" + + key_type: Optional[str] = None + """Specifies the type of the key used in the algorithm.""" + + message: Optional[str] = None + + public_key: Optional[str] = None + """Represents the public key used in the DS record.""" diff --git a/src/gcore/types/dns/zones/rrset_create_params.py b/src/gcore/types/dns/zones/rrset_create_params.py new file mode 100644 index 00000000..e4b2f876 --- /dev/null +++ b/src/gcore/types/dns/zones/rrset_create_params.py @@ -0,0 +1,84 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["RrsetCreateParams", "ResourceRecord", "Picker"] + + +class RrsetCreateParams(TypedDict, total=False): + zone_name: Required[Annotated[str, PropertyInfo(alias="zoneName")]] + + rrset_name: Required[Annotated[str, PropertyInfo(alias="rrsetName")]] + + resource_records: Required[Iterable[ResourceRecord]] + """List of resource record from rrset""" + + meta: Dict[str, object] + """Meta information for rrset""" + + pickers: Iterable[Picker] + """Set of pickers""" + + ttl: int + + +class ResourceRecord(TypedDict, total=False): + """nolint: lll""" + + content: Required[Iterable[object]] + """ + Content of resource record The exact length of the array depends on the type of + rrset, each individual record parameter must be a separate element of the array. + For example + + - SRV-record: `[100, 1, 5061, "example.com"]` + - CNAME-record: `[ "the.target.domain" ]` + - A-record: `[ "1.2.3.4", "5.6.7.8" ]` + - AAAA-record: `[ "2001:db8::1", "2001:db8::2" ]` + - MX-record: `[ "mail1.example.com", "mail2.example.com" ]` + - SVCB/HTTPS-record: + `[ 1, ".", ["alpn", "h3", "h2"], [ "port", 1443 ], [ "ipv4hint", "10.0.0.1" ], [ "ech", "AEn+DQBFKwAgACABWIHUGj4u+PIggYXcR5JF0gYk3dCRioBW8uJq9H4mKAAIAAEAAQABAANAEnB1YmxpYy50bHMtZWNoLmRldgAA" ] ]` + """ + + enabled: bool + + meta: Dict[str, object] + """ + This meta will be used to decide which resource record should pass through + filters from the filter set + """ + + +class Picker(TypedDict, total=False): + type: Required[ + Literal[ + "geodns", + "asn", + "country", + "continent", + "region", + "ip", + "geodistance", + "weighted_shuffle", + "default", + "first_n", + ] + ] + """Filter type""" + + limit: int + """ + Limits the number of records returned by the filter Can be a positive value for + a specific limit. Use zero or leave it blank to indicate no limits. + """ + + strict: bool + """ + if strict=false, then the filter will return all records if no records match the + filter + """ diff --git a/src/gcore/types/dns/zones/rrset_get_failover_logs_params.py b/src/gcore/types/dns/zones/rrset_get_failover_logs_params.py new file mode 100644 index 00000000..191c1b76 --- /dev/null +++ b/src/gcore/types/dns/zones/rrset_get_failover_logs_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["RrsetGetFailoverLogsParams"] + + +class RrsetGetFailoverLogsParams(TypedDict, total=False): + zone_name: Required[Annotated[str, PropertyInfo(alias="zoneName")]] + + rrset_name: Required[Annotated[str, PropertyInfo(alias="rrsetName")]] + + limit: int + """Max number of records in response""" + + offset: int + """Amount of records to skip before beginning to write in response.""" diff --git a/src/gcore/types/dns/zones/rrset_get_failover_logs_response.py b/src/gcore/types/dns/zones/rrset_get_failover_logs_response.py new file mode 100644 index 00000000..97a59100 --- /dev/null +++ b/src/gcore/types/dns/zones/rrset_get_failover_logs_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel +from .dns_failover_log import DNSFailoverLog + +__all__ = ["RrsetGetFailoverLogsResponse"] + + +class RrsetGetFailoverLogsResponse(BaseModel): + log: Optional[DNSFailoverLog] = None + """FailoverLog""" + + total_amount: Optional[int] = None diff --git a/src/gcore/types/dns/zones/rrset_list_params.py b/src/gcore/types/dns/zones/rrset_list_params.py new file mode 100644 index 00000000..39df19ef --- /dev/null +++ b/src/gcore/types/dns/zones/rrset_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["RrsetListParams"] + + +class RrsetListParams(TypedDict, total=False): + limit: int + """Max number of records in response""" + + offset: int + """Amount of records to skip before beginning to write in response.""" + + order_by: str + """Field name to sort by""" + + order_direction: Literal["asc", "desc"] + """Ascending or descending order""" diff --git a/src/gcore/types/dns/zones/rrset_list_response.py b/src/gcore/types/dns/zones/rrset_list_response.py new file mode 100644 index 00000000..1909ef98 --- /dev/null +++ b/src/gcore/types/dns/zones/rrset_list_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ...._models import BaseModel +from .dns_output_rrset import DNSOutputRrset + +__all__ = ["RrsetListResponse"] + + +class RrsetListResponse(BaseModel): + rrsets: Optional[List[DNSOutputRrset]] = None + + total_amount: Optional[int] = None diff --git a/src/gcore/types/dns/zones/rrset_replace_params.py b/src/gcore/types/dns/zones/rrset_replace_params.py new file mode 100644 index 00000000..46f6274c --- /dev/null +++ b/src/gcore/types/dns/zones/rrset_replace_params.py @@ -0,0 +1,84 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["RrsetReplaceParams", "ResourceRecord", "Picker"] + + +class RrsetReplaceParams(TypedDict, total=False): + zone_name: Required[Annotated[str, PropertyInfo(alias="zoneName")]] + + rrset_name: Required[Annotated[str, PropertyInfo(alias="rrsetName")]] + + resource_records: Required[Iterable[ResourceRecord]] + """List of resource record from rrset""" + + meta: Dict[str, object] + """Meta information for rrset""" + + pickers: Iterable[Picker] + """Set of pickers""" + + ttl: int + + +class ResourceRecord(TypedDict, total=False): + """nolint: lll""" + + content: Required[Iterable[object]] + """ + Content of resource record The exact length of the array depends on the type of + rrset, each individual record parameter must be a separate element of the array. + For example + + - SRV-record: `[100, 1, 5061, "example.com"]` + - CNAME-record: `[ "the.target.domain" ]` + - A-record: `[ "1.2.3.4", "5.6.7.8" ]` + - AAAA-record: `[ "2001:db8::1", "2001:db8::2" ]` + - MX-record: `[ "mail1.example.com", "mail2.example.com" ]` + - SVCB/HTTPS-record: + `[ 1, ".", ["alpn", "h3", "h2"], [ "port", 1443 ], [ "ipv4hint", "10.0.0.1" ], [ "ech", "AEn+DQBFKwAgACABWIHUGj4u+PIggYXcR5JF0gYk3dCRioBW8uJq9H4mKAAIAAEAAQABAANAEnB1YmxpYy50bHMtZWNoLmRldgAA" ] ]` + """ + + enabled: bool + + meta: Dict[str, object] + """ + This meta will be used to decide which resource record should pass through + filters from the filter set + """ + + +class Picker(TypedDict, total=False): + type: Required[ + Literal[ + "geodns", + "asn", + "country", + "continent", + "region", + "ip", + "geodistance", + "weighted_shuffle", + "default", + "first_n", + ] + ] + """Filter type""" + + limit: int + """ + Limits the number of records returned by the filter Can be a positive value for + a specific limit. Use zero or leave it blank to indicate no limits. + """ + + strict: bool + """ + if strict=false, then the filter will return all records if no records match the + filter + """ diff --git a/src/gcore/types/fastedge/__init__.py b/src/gcore/types/fastedge/__init__.py new file mode 100644 index 00000000..59553df9 --- /dev/null +++ b/src/gcore/types/fastedge/__init__.py @@ -0,0 +1,48 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .app import App as App +from .binary import Binary as Binary +from .client import Client as Client +from .secret import Secret as Secret +from .kv_store import KvStore as KvStore +from .template import Template as Template +from .app_param import AppParam as AppParam +from .app_short import AppShort as AppShort +from .call_status import CallStatus as CallStatus +from .binary_short import BinaryShort as BinaryShort +from .secret_short import SecretShort as SecretShort +from .duration_stats import DurationStats as DurationStats +from .kv_store_short import KvStoreShort as KvStoreShort +from .template_short import TemplateShort as TemplateShort +from .app_list_params import AppListParams as AppListParams +from .app_create_params import AppCreateParams as AppCreateParams +from .app_update_params import AppUpdateParams as AppUpdateParams +from .app_replace_params import AppReplaceParams as AppReplaceParams +from .secret_list_params import SecretListParams as SecretListParams +from .template_parameter import TemplateParameter as TemplateParameter +from .binary_create_params import BinaryCreateParams as BinaryCreateParams +from .binary_list_response import BinaryListResponse as BinaryListResponse +from .kv_store_list_params import KvStoreListParams as KvStoreListParams +from .secret_create_params import SecretCreateParams as SecretCreateParams +from .secret_delete_params import SecretDeleteParams as SecretDeleteParams +from .secret_list_response import SecretListResponse as SecretListResponse +from .secret_update_params import SecretUpdateParams as SecretUpdateParams +from .template_list_params import TemplateListParams as TemplateListParams +from .secret_replace_params import SecretReplaceParams as SecretReplaceParams +from .kv_store_create_params import KvStoreCreateParams as KvStoreCreateParams +from .kv_store_list_response import KvStoreListResponse as KvStoreListResponse +from .secret_create_response import SecretCreateResponse as SecretCreateResponse +from .template_create_params import TemplateCreateParams as TemplateCreateParams +from .template_delete_params import TemplateDeleteParams as TemplateDeleteParams +from .kv_store_replace_params import KvStoreReplaceParams as KvStoreReplaceParams +from .template_replace_params import TemplateReplaceParams as TemplateReplaceParams +from .kv_store_create_response import KvStoreCreateResponse as KvStoreCreateResponse +from .template_parameter_param import TemplateParameterParam as TemplateParameterParam +from .statistic_get_call_series_params import StatisticGetCallSeriesParams as StatisticGetCallSeriesParams +from .statistic_get_call_series_response import StatisticGetCallSeriesResponse as StatisticGetCallSeriesResponse +from .statistic_get_duration_series_params import StatisticGetDurationSeriesParams as StatisticGetDurationSeriesParams +from .statistic_get_duration_series_response import ( + StatisticGetDurationSeriesResponse as StatisticGetDurationSeriesResponse, +) diff --git a/src/gcore/types/fastedge/app.py b/src/gcore/types/fastedge/app.py new file mode 100644 index 00000000..d8cb8b41 --- /dev/null +++ b/src/gcore/types/fastedge/app.py @@ -0,0 +1,96 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["App", "Secrets", "Stores"] + + +class Secrets(BaseModel): + """Application secret short description""" + + id: int + """The unique identifier of the secret.""" + + comment: Optional[str] = None + """A description or comment about the secret.""" + + name: Optional[str] = None + """The unique name of the secret.""" + + +class Stores(BaseModel): + """Application stores""" + + id: int + """The identifier of the store""" + + comment: Optional[str] = None + """A description of the store""" + + name: Optional[str] = None + """The name of the store""" + + +class App(BaseModel): + api_type: Optional[str] = None + """Wasm API type""" + + binary: Optional[int] = None + """Binary ID""" + + comment: Optional[str] = None + """App description""" + + debug_until: Optional[datetime] = None + """When debugging finishes""" + + env: Optional[Dict[str, str]] = None + """Environment variables""" + + log: Optional[Literal["kafka", "none"]] = None + """Logging channel (by default - kafka, which allows exploring logs with API)""" + + name: Optional[str] = None + """App name""" + + networks: Optional[List[str]] = None + """Networks""" + + plan: Optional[str] = None + """Plan name""" + + plan_id: Optional[int] = None + """Plan ID""" + + rsp_headers: Optional[Dict[str, str]] = None + """Extra headers to add to the response""" + + secrets: Optional[Dict[str, Secrets]] = None + """Application secrets""" + + status: Optional[int] = None + """ + Status code: + 0 - draft (inactive) + 1 - enabled + 2 - disabled + 3 - hourly call limit exceeded + 4 - daily call limit exceeded + 5 - suspended + """ + + stores: Optional[Dict[str, Stores]] = None + """Application edge stores""" + + template: Optional[int] = None + """Template ID""" + + template_name: Optional[str] = None + """Template name""" + + url: Optional[str] = None + """App URL""" diff --git a/src/gcore/types/fastedge/app_create_params.py b/src/gcore/types/fastedge/app_create_params.py new file mode 100644 index 00000000..fa8f8f0f --- /dev/null +++ b/src/gcore/types/fastedge/app_create_params.py @@ -0,0 +1,65 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AppCreateParams", "Secrets", "Stores"] + + +class AppCreateParams(TypedDict, total=False): + binary: int + """Binary ID""" + + comment: str + """App description""" + + debug: bool + """Switch on logging for 30 minutes (switched off by default)""" + + env: Dict[str, str] + """Environment variables""" + + log: Optional[Literal["kafka", "none"]] + """Logging channel (by default - kafka, which allows exploring logs with API)""" + + name: str + """App name""" + + rsp_headers: Dict[str, str] + """Extra headers to add to the response""" + + secrets: Dict[str, Secrets] + """Application secrets""" + + status: int + """ + Status code: + 0 - draft (inactive) + 1 - enabled + 2 - disabled + 3 - hourly call limit exceeded + 4 - daily call limit exceeded + 5 - suspended + """ + + stores: Dict[str, Stores] + """Application edge stores""" + + template: int + """Template ID""" + + +class Secrets(TypedDict, total=False): + """Application secret short description""" + + id: Required[int] + """The unique identifier of the secret.""" + + +class Stores(TypedDict, total=False): + """Application stores""" + + id: Required[int] + """The identifier of the store""" diff --git a/src/gcore/types/fastedge/app_list_params.py b/src/gcore/types/fastedge/app_list_params.py new file mode 100644 index 00000000..e55c8558 --- /dev/null +++ b/src/gcore/types/fastedge/app_list_params.py @@ -0,0 +1,50 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["AppListParams"] + + +class AppListParams(TypedDict, total=False): + api_type: Literal["wasi-http", "proxy-wasm"] + """ + API type: + wasi-http - WASI with HTTP entry point + proxy-wasm - Proxy-Wasm app, callable from CDN + """ + + binary: int + """Binary ID""" + + limit: int + """Limit for pagination""" + + name: str + """Name of the app""" + + offset: int + """Offset for pagination""" + + ordering: Literal[ + "name", "-name", "status", "-status", "id", "-id", "template", "-template", "binary", "-binary", "plan", "-plan" + ] + """Ordering""" + + plan: int + """Plan ID""" + + status: int + """ + Status code: + 0 - draft (inactive) + 1 - enabled + 2 - disabled + 3 - hourly call limit exceeded + 4 - daily call limit exceeded + 5 - suspended + """ + + template: int + """Template ID""" diff --git a/src/gcore/types/fastedge/app_param.py b/src/gcore/types/fastedge/app_param.py new file mode 100644 index 00000000..c49448b8 --- /dev/null +++ b/src/gcore/types/fastedge/app_param.py @@ -0,0 +1,65 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AppParam", "Secrets", "Stores"] + + +class Secrets(TypedDict, total=False): + """Application secret short description""" + + id: Required[int] + """The unique identifier of the secret.""" + + +class Stores(TypedDict, total=False): + """Application stores""" + + id: Required[int] + """The identifier of the store""" + + +class AppParam(TypedDict, total=False): + binary: int + """Binary ID""" + + comment: str + """App description""" + + debug: bool + """Switch on logging for 30 minutes (switched off by default)""" + + env: Dict[str, str] + """Environment variables""" + + log: Optional[Literal["kafka", "none"]] + """Logging channel (by default - kafka, which allows exploring logs with API)""" + + name: str + """App name""" + + rsp_headers: Dict[str, str] + """Extra headers to add to the response""" + + secrets: Dict[str, Secrets] + """Application secrets""" + + status: int + """ + Status code: + 0 - draft (inactive) + 1 - enabled + 2 - disabled + 3 - hourly call limit exceeded + 4 - daily call limit exceeded + 5 - suspended + """ + + stores: Dict[str, Stores] + """Application edge stores""" + + template: int + """Template ID""" diff --git a/src/gcore/types/fastedge/app_replace_params.py b/src/gcore/types/fastedge/app_replace_params.py new file mode 100644 index 00000000..d0220c85 --- /dev/null +++ b/src/gcore/types/fastedge/app_replace_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from .app_param import AppParam + +__all__ = ["AppReplaceParams", "Body"] + + +class AppReplaceParams(TypedDict, total=False): + body: Body + + +class Body(AppParam, total=False): + pass diff --git a/src/gcore/types/fastedge/app_short.py b/src/gcore/types/fastedge/app_short.py new file mode 100644 index 00000000..e61d10f6 --- /dev/null +++ b/src/gcore/types/fastedge/app_short.py @@ -0,0 +1,60 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["AppShort"] + + +class AppShort(BaseModel): + id: int + """App ID""" + + api_type: str + """Wasm API type""" + + binary: int + """Binary ID""" + + name: str + """App name""" + + plan_id: int + """Application plan ID""" + + status: int + """ + Status code: + 0 - draft (inactive) + 1 - enabled + 2 - disabled + 3 - hourly call limit exceeded + 4 - daily call limit exceeded + 5 - suspended + """ + + comment: Optional[str] = None + """Description of the binary""" + + debug_until: Optional[datetime] = None + """When debugging finishes""" + + networks: Optional[List[str]] = None + """Networks""" + + plan: Optional[str] = None + """Application plan name""" + + template: Optional[int] = None + """Template ID""" + + template_name: Optional[str] = None + """Template name""" + + upgradeable_to: Optional[int] = None + """ID of the binary the app can be upgraded to""" + + url: Optional[str] = None + """App URL""" diff --git a/src/gcore/types/fastedge/app_update_params.py b/src/gcore/types/fastedge/app_update_params.py new file mode 100644 index 00000000..af917ce8 --- /dev/null +++ b/src/gcore/types/fastedge/app_update_params.py @@ -0,0 +1,65 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AppUpdateParams", "Secrets", "Stores"] + + +class AppUpdateParams(TypedDict, total=False): + binary: int + """Binary ID""" + + comment: str + """App description""" + + debug: bool + """Switch on logging for 30 minutes (switched off by default)""" + + env: Dict[str, str] + """Environment variables""" + + log: Optional[Literal["kafka", "none"]] + """Logging channel (by default - kafka, which allows exploring logs with API)""" + + name: str + """App name""" + + rsp_headers: Dict[str, str] + """Extra headers to add to the response""" + + secrets: Dict[str, Secrets] + """Application secrets""" + + status: int + """ + Status code: + 0 - draft (inactive) + 1 - enabled + 2 - disabled + 3 - hourly call limit exceeded + 4 - daily call limit exceeded + 5 - suspended + """ + + stores: Dict[str, Stores] + """Application edge stores""" + + template: int + """Template ID""" + + +class Secrets(TypedDict, total=False): + """Application secret short description""" + + id: Required[int] + """The unique identifier of the secret.""" + + +class Stores(TypedDict, total=False): + """Application stores""" + + id: Required[int] + """The identifier of the store""" diff --git a/src/gcore/types/fastedge/apps/__init__.py b/src/gcore/types/fastedge/apps/__init__.py new file mode 100644 index 00000000..b5a7180b --- /dev/null +++ b/src/gcore/types/fastedge/apps/__init__.py @@ -0,0 +1,6 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .log import Log as Log +from .log_list_params import LogListParams as LogListParams diff --git a/src/gcore/types/fastedge/apps/log.py b/src/gcore/types/fastedge/apps/log.py new file mode 100644 index 00000000..eb04e9de --- /dev/null +++ b/src/gcore/types/fastedge/apps/log.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from ...._models import BaseModel + +__all__ = ["Log"] + + +class Log(BaseModel): + id: Optional[str] = None + """Id of the log""" + + app_name: Optional[str] = None + """Name of the application""" + + client_ip: Optional[str] = None + """Client IP""" + + edge: Optional[str] = None + """Edge name""" + + log: Optional[str] = None + """Log message""" + + timestamp: Optional[datetime] = None + """Timestamp of a log in RFC3339 format""" diff --git a/src/gcore/types/fastedge/apps/log_list_params.py b/src/gcore/types/fastedge/apps/log_list_params.py new file mode 100644 index 00000000..8d53640a --- /dev/null +++ b/src/gcore/types/fastedge/apps/log_list_params.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Literal, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["LogListParams"] + + +class LogListParams(TypedDict, total=False): + client_ip: str + """Search by client IP""" + + edge: str + """Edge name""" + + from_: Annotated[Union[str, datetime], PropertyInfo(alias="from", format="iso8601")] + """Reporting period start time, RFC3339 format. Default 1 hour ago.""" + + limit: int + """Limit for pagination""" + + offset: int + """Offset for pagination""" + + search: str + """Search string""" + + sort: Literal["desc", "asc"] + """Sort order (default desc)""" + + to: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """Reporting period end time, RFC3339 format. Default current time in UTC.""" diff --git a/src/gcore/types/fastedge/binary.py b/src/gcore/types/fastedge/binary.py new file mode 100644 index 00000000..90a96496 --- /dev/null +++ b/src/gcore/types/fastedge/binary.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["Binary"] + + +class Binary(BaseModel): + id: int + """Binary ID""" + + api_type: str + """Wasm API type""" + + source: int + """ + Source language: + 0 - unknown + 1 - Rust + 2 - JavaScript + """ + + status: int + """ + Status code: + 0 - pending + 1 - compiled + 2 - compilation failed (errors available) + 3 - compilation failed (errors not available) + 4 - resulting binary exceeded the limit + 5 - unsupported source language + """ + + checksum: Optional[str] = None + """MD5 hash of the binary""" + + unref_since: Optional[str] = None + """Not used since (UTC)""" diff --git a/src/gcore/types/fastedge/binary_create_params.py b/src/gcore/types/fastedge/binary_create_params.py new file mode 100644 index 00000000..8231e29a --- /dev/null +++ b/src/gcore/types/fastedge/binary_create_params.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["BinaryCreateParams"] + + +class BinaryCreateParams(TypedDict, total=False): + pass diff --git a/src/gcore/types/fastedge/binary_list_response.py b/src/gcore/types/fastedge/binary_list_response.py new file mode 100644 index 00000000..b31a96b9 --- /dev/null +++ b/src/gcore/types/fastedge/binary_list_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .binary_short import BinaryShort + +__all__ = ["BinaryListResponse"] + + +class BinaryListResponse(BaseModel): + binaries: List[BinaryShort] diff --git a/src/gcore/types/fastedge/binary_short.py b/src/gcore/types/fastedge/binary_short.py new file mode 100644 index 00000000..e9ab6732 --- /dev/null +++ b/src/gcore/types/fastedge/binary_short.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["BinaryShort"] + + +class BinaryShort(BaseModel): + id: int + """Binary ID""" + + api_type: str + """Wasm API type""" + + status: int + """ + Status code: + 0 - pending + 1 - compiled + 2 - compilation failed (errors available) + 3 - compilation failed (errors not available) + 4 - resulting binary exceeded the limit + 5 - unsupported source language + """ + + checksum: Optional[str] = None + """MD5 hash of the binary""" + + unref_since: Optional[str] = None + """Not used since (UTC)""" diff --git a/src/gcore/types/fastedge/call_status.py b/src/gcore/types/fastedge/call_status.py new file mode 100644 index 00000000..0059f97f --- /dev/null +++ b/src/gcore/types/fastedge/call_status.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["CallStatus", "CountByStatus"] + + +class CountByStatus(BaseModel): + count: int + """Number of app calls""" + + status: int + """HTTP status""" + + +class CallStatus(BaseModel): + """Edge app call statistics""" + + count_by_status: List[CountByStatus] + """Count by status""" + + time: datetime + """Beginning ot reporting slot""" diff --git a/src/gcore/types/fastedge/client.py b/src/gcore/types/fastedge/client.py new file mode 100644 index 00000000..80cc2901 --- /dev/null +++ b/src/gcore/types/fastedge/client.py @@ -0,0 +1,48 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["Client", "Network"] + + +class Network(BaseModel): + is_default: bool + """Is network is default""" + + name: str + """Network name""" + + +class Client(BaseModel): + app_count: int + """Actual allowed number of apps""" + + daily_consumption: int + """Actual number of calls for all apps during the current day (UTC)""" + + hourly_consumption: int + """Actual number of calls for all apps during the current hour""" + + monthly_consumption: int + """Actual number of calls for all apps during the current calendar month (UTC)""" + + networks: List[Network] + """List of enabled networks""" + + plan_id: int + """Plan ID""" + + status: int + """ + Status code: + 1 - enabled + 2 - disabled + 3 - hourly call limit exceeded + 4 - daily call limit exceeded + 5 - suspended + """ + + plan: Optional[str] = None + """Plan name""" diff --git a/src/gcore/types/fastedge/duration_stats.py b/src/gcore/types/fastedge/duration_stats.py new file mode 100644 index 00000000..1c119e6e --- /dev/null +++ b/src/gcore/types/fastedge/duration_stats.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["DurationStats"] + + +class DurationStats(BaseModel): + """Edge app execution duration statistics""" + + avg: int + """Average duration in usec""" + + max: int + """Max duration in usec""" + + median: int + """Median (50% percentile) duration in usec""" + + min: int + """Min duration in usec""" + + perc75: int + """75% percentile duration in usec""" + + perc90: int + """90% percentile duration in usec""" + + time: datetime + """Beginning of reporting slot""" diff --git a/src/gcore/types/fastedge/kv_store.py b/src/gcore/types/fastedge/kv_store.py new file mode 100644 index 00000000..2b9a1d4c --- /dev/null +++ b/src/gcore/types/fastedge/kv_store.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["KvStore", "Byod"] + + +class Byod(BaseModel): + """BYOD (Bring Your Own Data) settings""" + + prefix: str + """Key prefix""" + + url: str + """URL to connect to""" + + +class KvStore(BaseModel): + name: str + """A name of the store""" + + app_count: Optional[int] = None + """The number of applications that use this store""" + + byod: Optional[Byod] = None + """BYOD (Bring Your Own Data) settings""" + + comment: Optional[str] = None + """A description of the store""" + + revision: Optional[int] = None + """Current store revision (only for non-BYOD stores)""" + + size: Optional[int] = None + """Total store size in bytes (zero for BYOD stores)""" + + updated_at: Optional[datetime] = None + """Timestamp of last store revision (only for non-BYOD stores)""" diff --git a/src/gcore/types/fastedge/kv_store_create_params.py b/src/gcore/types/fastedge/kv_store_create_params.py new file mode 100644 index 00000000..abd3df61 --- /dev/null +++ b/src/gcore/types/fastedge/kv_store_create_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["KvStoreCreateParams", "Byod"] + + +class KvStoreCreateParams(TypedDict, total=False): + name: Required[str] + """A name of the store""" + + byod: Byod + """BYOD (Bring Your Own Data) settings""" + + comment: str + """A description of the store""" + + +class Byod(TypedDict, total=False): + """BYOD (Bring Your Own Data) settings""" + + prefix: Required[str] + """Key prefix""" + + url: Required[str] + """URL to connect to""" diff --git a/src/gcore/types/fastedge/kv_store_create_response.py b/src/gcore/types/fastedge/kv_store_create_response.py new file mode 100644 index 00000000..cec6b49d --- /dev/null +++ b/src/gcore/types/fastedge/kv_store_create_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .kv_store import KvStore + +__all__ = ["KvStoreCreateResponse"] + + +class KvStoreCreateResponse(KvStore): + id: Optional[int] = None + """The unique identifier of the store.""" diff --git a/src/gcore/types/fastedge/kv_store_list_params.py b/src/gcore/types/fastedge/kv_store_list_params.py new file mode 100644 index 00000000..50bac08a --- /dev/null +++ b/src/gcore/types/fastedge/kv_store_list_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["KvStoreListParams"] + + +class KvStoreListParams(TypedDict, total=False): + app_id: int + """App ID""" + + limit: int + """Limit for pagination""" + + offset: int + """Offset for pagination""" diff --git a/src/gcore/types/fastedge/kv_store_list_response.py b/src/gcore/types/fastedge/kv_store_list_response.py new file mode 100644 index 00000000..4ed41cb5 --- /dev/null +++ b/src/gcore/types/fastedge/kv_store_list_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .kv_store_short import KvStoreShort + +__all__ = ["KvStoreListResponse"] + + +class KvStoreListResponse(BaseModel): + count: int + """Total number of stores""" + + stores: List[KvStoreShort] diff --git a/src/gcore/types/fastedge/kv_store_replace_params.py b/src/gcore/types/fastedge/kv_store_replace_params.py new file mode 100644 index 00000000..25b2b5bb --- /dev/null +++ b/src/gcore/types/fastedge/kv_store_replace_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["KvStoreReplaceParams", "Byod"] + + +class KvStoreReplaceParams(TypedDict, total=False): + name: Required[str] + """A name of the store""" + + byod: Byod + """BYOD (Bring Your Own Data) settings""" + + comment: str + """A description of the store""" + + +class Byod(TypedDict, total=False): + """BYOD (Bring Your Own Data) settings""" + + prefix: Required[str] + """Key prefix""" + + url: Required[str] + """URL to connect to""" diff --git a/src/gcore/types/fastedge/kv_store_short.py b/src/gcore/types/fastedge/kv_store_short.py new file mode 100644 index 00000000..7e3d0f55 --- /dev/null +++ b/src/gcore/types/fastedge/kv_store_short.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["KvStoreShort"] + + +class KvStoreShort(BaseModel): + id: int + """The unique identifier of the store""" + + app_count: int + """The number of applications that use this store""" + + name: str + """A name of the store""" + + comment: Optional[str] = None + """A description of the store""" + + size: Optional[int] = None + """Total store size in bytes""" diff --git a/src/gcore/types/fastedge/secret.py b/src/gcore/types/fastedge/secret.py new file mode 100644 index 00000000..bb29718f --- /dev/null +++ b/src/gcore/types/fastedge/secret.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["Secret", "SecretSlot"] + + +class SecretSlot(BaseModel): + slot: int + """Secret slot ID.""" + + checksum: Optional[str] = None + """A checksum of the secret value for integrity verification.""" + + +class Secret(BaseModel): + app_count: Optional[int] = None + """The number of applications that use this secret.""" + + comment: Optional[str] = None + """A description or comment about the secret.""" + + name: Optional[str] = None + """The unique name of the secret.""" + + secret_slots: Optional[List[SecretSlot]] = None + """A list of secret slots associated with this secret.""" diff --git a/src/gcore/types/fastedge/secret_create_params.py b/src/gcore/types/fastedge/secret_create_params.py new file mode 100644 index 00000000..861dcc02 --- /dev/null +++ b/src/gcore/types/fastedge/secret_create_params.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["SecretCreateParams", "SecretSlot"] + + +class SecretCreateParams(TypedDict, total=False): + name: Required[str] + """The unique name of the secret.""" + + comment: str + """A description or comment about the secret.""" + + secret_slots: Iterable[SecretSlot] + """A list of secret slots associated with this secret.""" + + +class SecretSlot(TypedDict, total=False): + slot: Required[int] + """Secret slot ID.""" + + value: str + """The value of the secret.""" diff --git a/src/gcore/types/fastedge/secret_create_response.py b/src/gcore/types/fastedge/secret_create_response.py new file mode 100644 index 00000000..39867464 --- /dev/null +++ b/src/gcore/types/fastedge/secret_create_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .secret import Secret + +__all__ = ["SecretCreateResponse"] + + +class SecretCreateResponse(Secret): + id: Optional[int] = None + """The unique identifier of the secret.""" diff --git a/src/gcore/types/fastedge/secret_delete_params.py b/src/gcore/types/fastedge/secret_delete_params.py new file mode 100644 index 00000000..3f275df7 --- /dev/null +++ b/src/gcore/types/fastedge/secret_delete_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["SecretDeleteParams"] + + +class SecretDeleteParams(TypedDict, total=False): + force: bool + """Force delete secret even if it is used in slots""" diff --git a/src/gcore/types/fastedge/secret_list_params.py b/src/gcore/types/fastedge/secret_list_params.py new file mode 100644 index 00000000..a867bb70 --- /dev/null +++ b/src/gcore/types/fastedge/secret_list_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["SecretListParams"] + + +class SecretListParams(TypedDict, total=False): + app_id: int + """App ID""" + + secret_name: str + """Secret name""" diff --git a/src/gcore/types/fastedge/secret_list_response.py b/src/gcore/types/fastedge/secret_list_response.py new file mode 100644 index 00000000..a8768eb2 --- /dev/null +++ b/src/gcore/types/fastedge/secret_list_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .secret_short import SecretShort + +__all__ = ["SecretListResponse"] + + +class SecretListResponse(BaseModel): + secrets: List[SecretShort] diff --git a/src/gcore/types/fastedge/secret_replace_params.py b/src/gcore/types/fastedge/secret_replace_params.py new file mode 100644 index 00000000..54ddc7f2 --- /dev/null +++ b/src/gcore/types/fastedge/secret_replace_params.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["SecretReplaceParams", "SecretSlot"] + + +class SecretReplaceParams(TypedDict, total=False): + name: Required[str] + """The unique name of the secret.""" + + comment: str + """A description or comment about the secret.""" + + secret_slots: Iterable[SecretSlot] + """A list of secret slots associated with this secret.""" + + +class SecretSlot(TypedDict, total=False): + slot: Required[int] + """Secret slot ID.""" + + value: str + """The value of the secret.""" diff --git a/src/gcore/types/fastedge/secret_short.py b/src/gcore/types/fastedge/secret_short.py new file mode 100644 index 00000000..147c604e --- /dev/null +++ b/src/gcore/types/fastedge/secret_short.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["SecretShort"] + + +class SecretShort(BaseModel): + name: str + """The unique name of the secret.""" + + id: Optional[int] = None + """The unique identifier of the secret.""" + + app_count: Optional[int] = None + """The number of applications that use this secret.""" + + comment: Optional[str] = None + """A description or comment about the secret.""" diff --git a/src/gcore/types/fastedge/secret_update_params.py b/src/gcore/types/fastedge/secret_update_params.py new file mode 100644 index 00000000..09a14344 --- /dev/null +++ b/src/gcore/types/fastedge/secret_update_params.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["SecretUpdateParams", "SecretSlot"] + + +class SecretUpdateParams(TypedDict, total=False): + comment: str + """A description or comment about the secret.""" + + name: str + """The unique name of the secret.""" + + secret_slots: Iterable[SecretSlot] + """A list of secret slots associated with this secret.""" + + +class SecretSlot(TypedDict, total=False): + slot: Required[int] + """Secret slot ID.""" + + value: str + """The value of the secret.""" diff --git a/src/gcore/types/fastedge/statistic_get_call_series_params.py b/src/gcore/types/fastedge/statistic_get_call_series_params.py new file mode 100644 index 00000000..a1cd6f68 --- /dev/null +++ b/src/gcore/types/fastedge/statistic_get_call_series_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetCallSeriesParams"] + + +class StatisticGetCallSeriesParams(TypedDict, total=False): + from_: Required[Annotated[Union[str, datetime], PropertyInfo(alias="from", format="iso8601")]] + """Reporting period start time, RFC3339 format""" + + step: Required[int] + """Reporting granularity, in seconds""" + + to: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """Reporting period end time (not included into reporting period), RFC3339 format""" + + id: int + """App ID""" + + network: str + """Network name""" diff --git a/src/gcore/types/fastedge/statistic_get_call_series_response.py b/src/gcore/types/fastedge/statistic_get_call_series_response.py new file mode 100644 index 00000000..aa06c88e --- /dev/null +++ b/src/gcore/types/fastedge/statistic_get_call_series_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .call_status import CallStatus + +__all__ = ["StatisticGetCallSeriesResponse"] + + +class StatisticGetCallSeriesResponse(BaseModel): + stats: List[CallStatus] diff --git a/src/gcore/types/fastedge/statistic_get_duration_series_params.py b/src/gcore/types/fastedge/statistic_get_duration_series_params.py new file mode 100644 index 00000000..c9170ee8 --- /dev/null +++ b/src/gcore/types/fastedge/statistic_get_duration_series_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetDurationSeriesParams"] + + +class StatisticGetDurationSeriesParams(TypedDict, total=False): + from_: Required[Annotated[Union[str, datetime], PropertyInfo(alias="from", format="iso8601")]] + """Reporting period start time, RFC3339 format""" + + step: Required[int] + """Reporting granularity, in seconds""" + + to: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """Reporting period end time (not included into reporting period), RFC3339 format""" + + id: int + """App ID""" + + network: str + """Network name""" diff --git a/src/gcore/types/fastedge/statistic_get_duration_series_response.py b/src/gcore/types/fastedge/statistic_get_duration_series_response.py new file mode 100644 index 00000000..0358ccc7 --- /dev/null +++ b/src/gcore/types/fastedge/statistic_get_duration_series_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .duration_stats import DurationStats + +__all__ = ["StatisticGetDurationSeriesResponse"] + + +class StatisticGetDurationSeriesResponse(BaseModel): + stats: List[DurationStats] diff --git a/src/gcore/types/fastedge/template.py b/src/gcore/types/fastedge/template.py new file mode 100644 index 00000000..71efe55c --- /dev/null +++ b/src/gcore/types/fastedge/template.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .template_parameter import TemplateParameter + +__all__ = ["Template"] + + +class Template(BaseModel): + api_type: str + """Wasm API type""" + + binary_id: int + """Binary ID""" + + name: str + """Name of the template""" + + owned: bool + """Is the template owned by user?""" + + params: List[TemplateParameter] + """Parameters""" + + long_descr: Optional[str] = None + """Long description of the template""" + + short_descr: Optional[str] = None + """Short description of the template""" diff --git a/src/gcore/types/fastedge/template_create_params.py b/src/gcore/types/fastedge/template_create_params.py new file mode 100644 index 00000000..e5f2ad12 --- /dev/null +++ b/src/gcore/types/fastedge/template_create_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +from .template_parameter_param import TemplateParameterParam + +__all__ = ["TemplateCreateParams"] + + +class TemplateCreateParams(TypedDict, total=False): + binary_id: Required[int] + """Binary ID""" + + name: Required[str] + """Name of the template""" + + owned: Required[bool] + """Is the template owned by user?""" + + params: Required[Iterable[TemplateParameterParam]] + """Parameters""" + + long_descr: str + """Long description of the template""" + + short_descr: str + """Short description of the template""" diff --git a/src/gcore/types/fastedge/template_delete_params.py b/src/gcore/types/fastedge/template_delete_params.py new file mode 100644 index 00000000..e403aa0e --- /dev/null +++ b/src/gcore/types/fastedge/template_delete_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["TemplateDeleteParams"] + + +class TemplateDeleteParams(TypedDict, total=False): + force: bool + """Force template deletion even if it is shared to groups""" diff --git a/src/gcore/types/fastedge/template_list_params.py b/src/gcore/types/fastedge/template_list_params.py new file mode 100644 index 00000000..09009d39 --- /dev/null +++ b/src/gcore/types/fastedge/template_list_params.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["TemplateListParams"] + + +class TemplateListParams(TypedDict, total=False): + api_type: Literal["wasi-http", "proxy-wasm"] + """ + API type: + wasi-http - WASI with HTTP entry point + proxy-wasm - Proxy-Wasm app, callable from CDN + """ + + limit: int + """Limit for pagination""" + + offset: int + """Offset for pagination""" + + only_mine: bool + """Only my templates""" diff --git a/src/gcore/types/fastedge/template_parameter.py b/src/gcore/types/fastedge/template_parameter.py new file mode 100644 index 00000000..48249128 --- /dev/null +++ b/src/gcore/types/fastedge/template_parameter.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["TemplateParameter"] + + +class TemplateParameter(BaseModel): + data_type: Literal["string", "number", "date", "time", "secret", "store"] + """Parameter type""" + + mandatory: bool + """Is this field mandatory?""" + + name: str + """Parameter name""" + + descr: Optional[str] = None + """Parameter description""" diff --git a/src/gcore/types/fastedge/template_parameter_param.py b/src/gcore/types/fastedge/template_parameter_param.py new file mode 100644 index 00000000..ee5fb80f --- /dev/null +++ b/src/gcore/types/fastedge/template_parameter_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["TemplateParameterParam"] + + +class TemplateParameterParam(TypedDict, total=False): + data_type: Required[Literal["string", "number", "date", "time", "secret", "store"]] + """Parameter type""" + + mandatory: Required[bool] + """Is this field mandatory?""" + + name: Required[str] + """Parameter name""" + + descr: str + """Parameter description""" diff --git a/src/gcore/types/fastedge/template_replace_params.py b/src/gcore/types/fastedge/template_replace_params.py new file mode 100644 index 00000000..214b22f6 --- /dev/null +++ b/src/gcore/types/fastedge/template_replace_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +from .template_parameter_param import TemplateParameterParam + +__all__ = ["TemplateReplaceParams"] + + +class TemplateReplaceParams(TypedDict, total=False): + binary_id: Required[int] + """Binary ID""" + + name: Required[str] + """Name of the template""" + + owned: Required[bool] + """Is the template owned by user?""" + + params: Required[Iterable[TemplateParameterParam]] + """Parameters""" + + long_descr: str + """Long description of the template""" + + short_descr: str + """Short description of the template""" diff --git a/src/gcore/types/fastedge/template_short.py b/src/gcore/types/fastedge/template_short.py new file mode 100644 index 00000000..feed4c89 --- /dev/null +++ b/src/gcore/types/fastedge/template_short.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["TemplateShort"] + + +class TemplateShort(BaseModel): + id: int + """Template ID""" + + api_type: str + """Wasm API type""" + + name: str + """Name of the template""" + + owned: bool + """Is the template owned by user?""" + + long_descr: Optional[str] = None + """Long description of the template""" + + short_descr: Optional[str] = None + """Short description of the template""" diff --git a/src/gcore/types/iam/__init__.py b/src/gcore/types/iam/__init__.py new file mode 100644 index 00000000..849d7323 --- /dev/null +++ b/src/gcore/types/iam/__init__.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .user import User as User +from .api_token import APIToken as APIToken +from .user_invite import UserInvite as UserInvite +from .user_updated import UserUpdated as UserUpdated +from .user_detailed import UserDetailed as UserDetailed +from .api_token_list import APITokenList as APITokenList +from .account_overview import AccountOverview as AccountOverview +from .user_list_params import UserListParams as UserListParams +from .api_token_created import APITokenCreated as APITokenCreated +from .user_invite_params import UserInviteParams as UserInviteParams +from .user_update_params import UserUpdateParams as UserUpdateParams +from .api_token_list_params import APITokenListParams as APITokenListParams +from .api_token_create_params import APITokenCreateParams as APITokenCreateParams diff --git a/src/gcore/types/iam/account_overview.py b/src/gcore/types/iam/account_overview.py new file mode 100644 index 00000000..ad8a265e --- /dev/null +++ b/src/gcore/types/iam/account_overview.py @@ -0,0 +1,527 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = [ + "AccountOverview", + "FreeFeatures", + "FreeFeaturesCDN", + "FreeFeaturesCloud", + "FreeFeaturesDDOS", + "FreeFeaturesDNS", + "FreeFeaturesStorage", + "FreeFeaturesStreaming", + "PaidFeatures", + "PaidFeaturesCDN", + "PaidFeaturesCloud", + "PaidFeaturesDDOS", + "PaidFeaturesDNS", + "PaidFeaturesStorage", + "PaidFeaturesStreaming", + "ServiceStatuses", + "ServiceStatusesCDN", + "ServiceStatusesCloud", + "ServiceStatusesDDOS", + "ServiceStatusesDNS", + "ServiceStatusesStorage", + "ServiceStatusesStreaming", + "User", + "UserGroup", +] + + +class FreeFeaturesCDN(BaseModel): + """Feature object.""" + + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8086/RFC 3339 format).""" + + feature_id: Optional[int] = None + """Feature ID.""" + + free_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + name: Optional[str] = None + """Name of the feature.""" + + service: Optional[Literal["CDN", "STORAGE", "STREAMING", "DNS", "DDOS", "CLOUD"]] = None + """Service's name.""" + + +class FreeFeaturesCloud(BaseModel): + """Feature object.""" + + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8086/RFC 3339 format).""" + + feature_id: Optional[int] = None + """Feature ID.""" + + free_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + name: Optional[str] = None + """Name of the feature.""" + + service: Optional[Literal["CDN", "STORAGE", "STREAMING", "DNS", "DDOS", "CLOUD"]] = None + """Service's name.""" + + +class FreeFeaturesDDOS(BaseModel): + """Feature object.""" + + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8086/RFC 3339 format).""" + + feature_id: Optional[int] = None + """Feature ID.""" + + free_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + name: Optional[str] = None + """Name of the feature.""" + + service: Optional[Literal["CDN", "STORAGE", "STREAMING", "DNS", "DDOS", "CLOUD"]] = None + """Service's name.""" + + +class FreeFeaturesDNS(BaseModel): + """Feature object.""" + + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8086/RFC 3339 format).""" + + feature_id: Optional[int] = None + """Feature ID.""" + + free_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + name: Optional[str] = None + """Name of the feature.""" + + service: Optional[Literal["CDN", "STORAGE", "STREAMING", "DNS", "DDOS", "CLOUD"]] = None + """Service's name.""" + + +class FreeFeaturesStorage(BaseModel): + """Feature object.""" + + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8086/RFC 3339 format).""" + + feature_id: Optional[int] = None + """Feature ID.""" + + free_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + name: Optional[str] = None + """Name of the feature.""" + + service: Optional[Literal["CDN", "STORAGE", "STREAMING", "DNS", "DDOS", "CLOUD"]] = None + """Service's name.""" + + +class FreeFeaturesStreaming(BaseModel): + """Feature object.""" + + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8086/RFC 3339 format).""" + + feature_id: Optional[int] = None + """Feature ID.""" + + free_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + name: Optional[str] = None + """Name of the feature.""" + + service: Optional[Literal["CDN", "STORAGE", "STREAMING", "DNS", "DDOS", "CLOUD"]] = None + """Service's name.""" + + +class FreeFeatures(BaseModel): + """ + An object of arrays which contains information about free features available for the requested account. + """ + + cdn: Optional[List[FreeFeaturesCDN]] = FieldInfo(alias="CDN", default=None) + + cloud: Optional[List[FreeFeaturesCloud]] = FieldInfo(alias="CLOUD", default=None) + + ddos: Optional[List[FreeFeaturesDDOS]] = FieldInfo(alias="DDOS", default=None) + + dns: Optional[List[FreeFeaturesDNS]] = FieldInfo(alias="DNS", default=None) + + storage: Optional[List[FreeFeaturesStorage]] = FieldInfo(alias="STORAGE", default=None) + + streaming: Optional[List[FreeFeaturesStreaming]] = FieldInfo(alias="STREAMING", default=None) + + +class PaidFeaturesCDN(BaseModel): + """Feature object.""" + + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8086/RFC 3339 format).""" + + feature_id: Optional[int] = None + """Feature ID.""" + + name: Optional[str] = None + """Name of the feature.""" + + paid_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + service: Optional[Literal["CDN", "STORAGE", "STREAMING", "DNS", "DDOS", "CLOUD"]] = None + """Service's name.""" + + +class PaidFeaturesCloud(BaseModel): + """Feature object.""" + + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8086/RFC 3339 format).""" + + feature_id: Optional[int] = None + """Feature ID.""" + + name: Optional[str] = None + """Name of the feature.""" + + paid_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + service: Optional[Literal["CDN", "STORAGE", "STREAMING", "DNS", "DDOS", "CLOUD"]] = None + """Service's name.""" + + +class PaidFeaturesDDOS(BaseModel): + """Feature object.""" + + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8086/RFC 3339 format).""" + + feature_id: Optional[int] = None + """Feature ID.""" + + name: Optional[str] = None + """Name of the feature.""" + + paid_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + service: Optional[Literal["CDN", "STORAGE", "STREAMING", "DNS", "DDOS", "CLOUD"]] = None + """Service's name.""" + + +class PaidFeaturesDNS(BaseModel): + """Feature object.""" + + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8086/RFC 3339 format).""" + + feature_id: Optional[int] = None + """Feature ID.""" + + name: Optional[str] = None + """Name of the feature.""" + + paid_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + service: Optional[Literal["CDN", "STORAGE", "STREAMING", "DNS", "DDOS", "CLOUD"]] = None + """Service's name.""" + + +class PaidFeaturesStorage(BaseModel): + """Feature object.""" + + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8086/RFC 3339 format).""" + + feature_id: Optional[int] = None + """Feature ID.""" + + name: Optional[str] = None + """Name of the feature.""" + + paid_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + service: Optional[Literal["CDN", "STORAGE", "STREAMING", "DNS", "DDOS", "CLOUD"]] = None + """Service's name.""" + + +class PaidFeaturesStreaming(BaseModel): + """Feature object.""" + + create_date: Optional[str] = None + """Date and time when the feature was activated (ISO 8086/RFC 3339 format).""" + + feature_id: Optional[int] = None + """Feature ID.""" + + name: Optional[str] = None + """Name of the feature.""" + + paid_feature_id: Optional[int] = None + """Internal feature activation ID.""" + + service: Optional[Literal["CDN", "STORAGE", "STREAMING", "DNS", "DDOS", "CLOUD"]] = None + """Service's name.""" + + +class PaidFeatures(BaseModel): + """ + An object of arrays which contains information about paid features available for the requested account. + """ + + cdn: Optional[List[PaidFeaturesCDN]] = FieldInfo(alias="CDN", default=None) + + cloud: Optional[List[PaidFeaturesCloud]] = FieldInfo(alias="CLOUD", default=None) + + ddos: Optional[List[PaidFeaturesDDOS]] = FieldInfo(alias="DDOS", default=None) + + dns: Optional[List[PaidFeaturesDNS]] = FieldInfo(alias="DNS", default=None) + + storage: Optional[List[PaidFeaturesStorage]] = FieldInfo(alias="STORAGE", default=None) + + streaming: Optional[List[PaidFeaturesStreaming]] = FieldInfo(alias="STREAMING", default=None) + + +class ServiceStatusesCDN(BaseModel): + enabled: Optional[bool] = None + """`true` - service is available in the Control Panel.""" + + status: Optional[Literal["new", "trial", "trialend", "active", "paused", "activating", "deleted"]] = None + """Status of the service.""" + + +class ServiceStatusesCloud(BaseModel): + enabled: Optional[bool] = None + """`true` - service is available in the Control Panel.""" + + status: Optional[Literal["new", "trial", "trialend", "active", "paused", "activating", "deleted"]] = None + """Status of the service.""" + + +class ServiceStatusesDDOS(BaseModel): + enabled: Optional[bool] = None + """`true` - service is available in the Control Panel.""" + + status: Optional[Literal["new", "trial", "trialend", "active", "paused", "activating", "deleted"]] = None + """Status of the service.""" + + +class ServiceStatusesDNS(BaseModel): + enabled: Optional[bool] = None + """`true` - service is available in the Control Panel.""" + + status: Optional[Literal["new", "trial", "trialend", "active", "paused", "activating", "deleted"]] = None + """Status of the service.""" + + +class ServiceStatusesStorage(BaseModel): + enabled: Optional[bool] = None + """`true` - service is available in the Control Panel.""" + + status: Optional[Literal["new", "trial", "trialend", "active", "paused", "activating", "deleted"]] = None + """Status of the service.""" + + +class ServiceStatusesStreaming(BaseModel): + enabled: Optional[bool] = None + """`true` - service is available in the Control Panel.""" + + status: Optional[Literal["new", "trial", "trialend", "active", "paused", "activating", "deleted"]] = None + """Status of the service.""" + + +class ServiceStatuses(BaseModel): + """ + An object of arrays which contains information about all services available for the requested account. + """ + + cdn: Optional[ServiceStatusesCDN] = FieldInfo(alias="CDN", default=None) + + cloud: Optional[ServiceStatusesCloud] = FieldInfo(alias="CLOUD", default=None) + + ddos: Optional[ServiceStatusesDDOS] = FieldInfo(alias="DDOS", default=None) + + dns: Optional[ServiceStatusesDNS] = FieldInfo(alias="DNS", default=None) + + storage: Optional[ServiceStatusesStorage] = FieldInfo(alias="STORAGE", default=None) + + streaming: Optional[ServiceStatusesStreaming] = FieldInfo(alias="STREAMING", default=None) + + +class UserGroup(BaseModel): + id: Optional[int] = None + """Group's ID: Possible values are: + + - 1 - Administrators* 2 - Users* 5 - Engineers* 3009 - Purge and Prefetch only + (API+Web)* 3022 - Purge and Prefetch only (API) + """ + + name: Optional[ + Literal[ + "Users", "Administrators", "Engineers", "Purge and Prefetch only (API)", "Purge and Prefetch only (API+Web)" + ] + ] = None + """Group's name.""" + + +class User(BaseModel): + id: Optional[int] = None + """User's ID.""" + + activated: Optional[bool] = None + """Email confirmation: + + - `true` – user confirmed the email; + - `false` – user did not confirm the email. + """ + + auth_types: Optional[List[Literal["password", "sso", "github", "google-oauth2"]]] = None + """System field. List of auth types available for the account.""" + + client: Optional[float] = None + """User's account ID.""" + + company: Optional[str] = None + """User's company.""" + + deleted: Optional[bool] = None + """Deletion flag. If `true` then user was deleted.""" + + email: Optional[str] = None + """User's email address.""" + + groups: Optional[List[UserGroup]] = None + """User's group in the current account. + + IAM supports 5 groups: + + - Users + - Administrators + - Engineers + - Purge and Prefetch only (API) + - Purge and Prefetch only (API+Web) + """ + + lang: Optional[Literal["de", "en", "ru", "zh", "az"]] = None + """User's language. + + Defines language of the control panel and email messages. + """ + + name: Optional[str] = None + """User's name.""" + + phone: Optional[str] = None + """User's phone.""" + + reseller: Optional[int] = None + """Services provider ID.""" + + sso_auth: Optional[bool] = None + """SSO authentication flag. If `true` then user can login via SAML SSO.""" + + two_fa: Optional[bool] = None + """Two-step verification: + + - `true` – user enabled two-step verification; + - `false` – user disabled two-step verification. + """ + + +class AccountOverview(BaseModel): + id: int + """The account ID.""" + + bill_type: str + """System field. Billing type of the account.""" + + capabilities: List[Literal["CDN", "STORAGE", "STREAMING", "DNS", "DDOS", "CLOUD"]] + """System field. List of services available for the account.""" + + company_name: str = FieldInfo(alias="companyName") + """The company name.""" + + current_user: int = FieldInfo(alias="currentUser") + """ID of the current user.""" + + deleted: bool + """The field shows the status of the account: + + - `true` – the account has been deleted + - `false` – the account is not deleted + """ + + email: str + """The account email.""" + + entry_base_domain: Optional[str] = FieldInfo(alias="entryBaseDomain", default=None) + """System field. Control panel domain.""" + + free_features: FreeFeatures = FieldInfo(alias="freeFeatures") + """ + An object of arrays which contains information about free features available for + the requested account. + """ + + has_active_admin: bool + """System field.""" + + is_test: bool + """System field: + + - `true` — a test account; + - `false` — a production account. + """ + + name: Optional[str] = None + """Name of a user who registered the requested account.""" + + paid_features: PaidFeatures = FieldInfo(alias="paidFeatures") + """ + An object of arrays which contains information about paid features available for + the requested account. + """ + + service_statuses: ServiceStatuses = FieldInfo(alias="serviceStatuses") + """ + An object of arrays which contains information about all services available for + the requested account. + """ + + status: Literal["new", "trial", "trialend", "active", "integration", "paused", "preparation", "ready"] + """Status of the account.""" + + country_code: Optional[str] = None + """System field. The company country (ISO 3166-1 alpha-2 format).""" + + custom_id: Optional[str] = None + """The account custom ID.""" + + phone: Optional[str] = None + """Phone of a user who registered the requested account.""" + + signup_process: Optional[Literal["sign_up_full", "sign_up_simple"]] = None + """System field. Type of the account registration process.""" + + users: Optional[List[User]] = None + """List of account users.""" + + website: Optional[str] = None + """The company website.""" diff --git a/src/gcore/types/iam/api_token.py b/src/gcore/types/iam/api_token.py new file mode 100644 index 00000000..0348d230 --- /dev/null +++ b/src/gcore/types/iam/api_token.py @@ -0,0 +1,78 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["APIToken", "ClientUser", "ClientUserRole"] + + +class ClientUserRole(BaseModel): + id: Optional[int] = None + """Group's ID: Possible values are: + + - 1 - Administrators* 2 - Users* 5 - Engineers* 3009 - Purge and Prefetch only + (API+Web)* 3022 - Purge and Prefetch only (API) + """ + + name: Optional[ + Literal[ + "Users", "Administrators", "Engineers", "Purge and Prefetch only (API)", "Purge and Prefetch only (API+Web)" + ] + ] = None + """Group's name.""" + + +class ClientUser(BaseModel): + client_id: int + """Account's ID.""" + + deleted: bool + """Deletion flag. If true, then the API token was deleted.""" + + role: ClientUserRole + + user_email: str + """User's email who issued the API token.""" + + user_id: int + """User's ID who issued the API token.""" + + user_name: str + """User's name who issued the API token.""" + + +class APIToken(BaseModel): + id: int + """API token ID.""" + + client_user: ClientUser + + created: str + """Date when the API token was issued (ISO 8086/RFC 3339 format), UTC.""" + + deleted: bool + """Deletion flag. If true, then the API token was deleted.""" + + exp_date: Optional[str] = None + """ + Date when the API token becomes expired (ISO 8086/RFC 3339 format), UTC. If + null, then the API token will never expire. + """ + + expired: bool + """Expiration flag. + + If true, then the API token has expired. When an API token expires it will be + automatically deleted. + """ + + last_usage: str + """Date when the API token was last used (ISO 8086/RFC 3339 format), UTC.""" + + name: str + """API token name.""" + + description: Optional[str] = None + """API token description.""" diff --git a/src/gcore/types/iam/api_token_create_params.py b/src/gcore/types/iam/api_token_create_params.py new file mode 100644 index 00000000..c8ba1f0e --- /dev/null +++ b/src/gcore/types/iam/api_token_create_params.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["APITokenCreateParams", "ClientUser", "ClientUserRole"] + + +class APITokenCreateParams(TypedDict, total=False): + client_user: Required[ClientUser] + """API token role.""" + + exp_date: Required[Optional[str]] + """ + Date when the API token becomes expired (ISO 8086/RFC 3339 format), UTC. If + null, then the API token will never expire. + """ + + name: Required[str] + """API token name.""" + + description: str + """API token description.""" + + +class ClientUserRole(TypedDict, total=False): + id: int + """Group's ID: Possible values are: + + - 1 - Administrators* 2 - Users* 5 - Engineers* 3009 - Purge and Prefetch only + (API+Web)* 3022 - Purge and Prefetch only (API) + """ + + name: Literal[ + "Users", "Administrators", "Engineers", "Purge and Prefetch only (API)", "Purge and Prefetch only (API+Web)" + ] + """Group's name.""" + + +class ClientUser(TypedDict, total=False): + """API token role.""" + + role: ClientUserRole diff --git a/src/gcore/types/iam/api_token_created.py b/src/gcore/types/iam/api_token_created.py new file mode 100644 index 00000000..be3c3ff3 --- /dev/null +++ b/src/gcore/types/iam/api_token_created.py @@ -0,0 +1,84 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["APITokenCreated", "ClientUser", "ClientUserRole"] + + +class ClientUserRole(BaseModel): + id: Optional[int] = None + """Group's ID: Possible values are: + + - 1 - Administrators* 2 - Users* 5 - Engineers* 3009 - Purge and Prefetch only + (API+Web)* 3022 - Purge and Prefetch only (API) + """ + + name: Optional[ + Literal[ + "Users", "Administrators", "Engineers", "Purge and Prefetch only (API)", "Purge and Prefetch only (API+Web)" + ] + ] = None + """Group's name.""" + + +class ClientUser(BaseModel): + client_id: int + """Account's ID.""" + + deleted: bool + """Deletion flag. If true, then the API token was deleted.""" + + role: ClientUserRole + + user_email: str + """User's email who issued the API token.""" + + user_id: int + """User's ID who issued the API token.""" + + user_name: str + """User's name who issued the API token.""" + + +class APITokenCreated(BaseModel): + id: int + """API token ID.""" + + client_user: ClientUser + + created: str + """Date when the API token was issued (ISO 8086/RFC 3339 format), UTC.""" + + deleted: bool + """Deletion flag. If true, then the API token was deleted.""" + + exp_date: Optional[str] = None + """ + Date when the API token becomes expired (ISO 8086/RFC 3339 format), UTC. If + null, then the API token will never expire. + """ + + expired: bool + """Expiration flag. + + If true, then the API token has expired. When an API token expires it will be + automatically deleted. + """ + + last_usage: str + """Date when the API token was last used (ISO 8086/RFC 3339 format), UTC.""" + + name: str + """API token name.""" + + token: Optional[str] = None + """ + API token. Copy it, because you will not be able to get it again. We do not + store tokens. All responsibility for token storage and usage is on the issuer. + """ + + description: Optional[str] = None + """API token description.""" diff --git a/src/gcore/types/iam/api_token_list.py b/src/gcore/types/iam/api_token_list.py new file mode 100644 index 00000000..2bf046b6 --- /dev/null +++ b/src/gcore/types/iam/api_token_list.py @@ -0,0 +1,81 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel + +__all__ = ["APITokenList", "APITokenListItem", "APITokenListItemClientUser", "APITokenListItemClientUserRole"] + + +class APITokenListItemClientUserRole(BaseModel): + id: Optional[int] = None + """Group's ID: Possible values are: + + - 1 - Administrators* 2 - Users* 5 - Engineers* 3009 - Purge and Prefetch only + (API+Web)* 3022 - Purge and Prefetch only (API) + """ + + name: Optional[ + Literal[ + "Users", "Administrators", "Engineers", "Purge and Prefetch only (API)", "Purge and Prefetch only (API+Web)" + ] + ] = None + """Group's name.""" + + +class APITokenListItemClientUser(BaseModel): + client_id: int + """Account's ID.""" + + deleted: bool + """Deletion flag. If true, then the API token was deleted.""" + + role: APITokenListItemClientUserRole + + user_email: str + """User's email who issued the API token.""" + + user_id: int + """User's ID who issued the API token.""" + + user_name: str + """User's name who issued the API token.""" + + +class APITokenListItem(BaseModel): + id: int + """API token ID.""" + + client_user: APITokenListItemClientUser + + created: str + """Date when the API token was issued (ISO 8086/RFC 3339 format), UTC.""" + + deleted: bool + """Deletion flag. If true, then the API token was deleted.""" + + exp_date: Optional[str] = None + """ + Date when the API token becomes expired (ISO 8086/RFC 3339 format), UTC. If + null, then the API token will never expire. + """ + + expired: bool + """Expiration flag. + + If true, then the API token has expired. When an API token expires it will be + automatically deleted. + """ + + last_usage: str + """Date when the API token was last used (ISO 8086/RFC 3339 format), UTC.""" + + name: str + """API token name.""" + + description: Optional[str] = None + """API token description.""" + + +APITokenList: TypeAlias = List[APITokenListItem] diff --git a/src/gcore/types/iam/api_token_list_params.py b/src/gcore/types/iam/api_token_list_params.py new file mode 100644 index 00000000..b185e501 --- /dev/null +++ b/src/gcore/types/iam/api_token_list_params.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["APITokenListParams"] + + +class APITokenListParams(TypedDict, total=False): + deleted: bool + """The state of API tokens included in the response. + Two possible values: + + - True - API token was not deleted.\\** False - API token was deleted. + + Example, _&deleted=True_ + """ + + issued_by: int + """User's ID. + + Use to get API tokens issued by a particular user. + Example, _&`issued_by`=1234_ + """ + + not_issued_by: int + """User's ID. + + Use to get API tokens issued by anyone except a particular user. + Example, _¬_issued_by=1234_ + """ + + role: str + """Group's ID. Possible values are: + + - 1 - Administrators* 2 - Users* 5 - Engineers* 3009 - Purge and Prefetch only + (API+Web)* 3022 - Purge and Prefetch only (API) + + Example, _&role=Engineers_ + """ diff --git a/src/gcore/types/iam/user.py b/src/gcore/types/iam/user.py new file mode 100644 index 00000000..0dcaa14b --- /dev/null +++ b/src/gcore/types/iam/user.py @@ -0,0 +1,109 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["User", "ClientAndRole", "Group"] + + +class ClientAndRole(BaseModel): + client_company_name: str + + client_id: int + + user_id: int + """User's ID.""" + + user_roles: List[str] + """User role in this client.""" + + +class Group(BaseModel): + id: Optional[int] = None + """Group's ID: Possible values are: + + - 1 - Administrators* 2 - Users* 5 - Engineers* 3009 - Purge and Prefetch only + (API+Web)* 3022 - Purge and Prefetch only (API) + """ + + name: Optional[ + Literal[ + "Users", "Administrators", "Engineers", "Purge and Prefetch only (API)", "Purge and Prefetch only (API+Web)" + ] + ] = None + """Group's name.""" + + +class User(BaseModel): + id: int + """User's ID.""" + + activated: bool + """Email confirmation: + + - `true` – user confirmed the email; + - `false` – user did not confirm the email. + """ + + auth_types: List[Literal["password", "sso", "github", "google-oauth2"]] + """System field. List of auth types available for the account.""" + + client: float + """User's account ID.""" + + client_and_roles: List[ClientAndRole] + """List of user's clients. User can access to one or more clients.""" + + company: str + """User's company.""" + + deleted: bool + """Deletion flag. If `true` then user was deleted.""" + + email: str + """User's email address.""" + + groups: List[Group] + """User's group in the current account. + + IAM supports 5 groups: + + - Users + - Administrators + - Engineers + - Purge and Prefetch only (API) + - Purge and Prefetch only (API+Web) + """ + + is_active: bool + """User activity flag.""" + + lang: Literal["de", "en", "ru", "zh", "az"] + """User's language. + + Defines language of the control panel and email messages. + """ + + name: Optional[str] = None + """User's name.""" + + phone: Optional[str] = None + """User's phone.""" + + reseller: int + """Services provider ID.""" + + sso_auth: bool + """SSO authentication flag. If `true` then user can login via SAML SSO.""" + + two_fa: bool + """Two-step verification: + + - `true` – user enabled two-step verification; + - `false` – user disabled two-step verification. + """ + + user_type: Literal["common", "reseller", "seller"] + """User's type.""" diff --git a/src/gcore/types/iam/user_detailed.py b/src/gcore/types/iam/user_detailed.py new file mode 100644 index 00000000..976262c5 --- /dev/null +++ b/src/gcore/types/iam/user_detailed.py @@ -0,0 +1,109 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["UserDetailed", "ClientAndRole", "Group"] + + +class ClientAndRole(BaseModel): + client_company_name: str + + client_id: int + + user_id: int + """User's ID.""" + + user_roles: List[str] + """User role in this client.""" + + +class Group(BaseModel): + id: Optional[int] = None + """Group's ID: Possible values are: + + - 1 - Administrators* 2 - Users* 5 - Engineers* 3009 - Purge and Prefetch only + (API+Web)* 3022 - Purge and Prefetch only (API) + """ + + name: Optional[ + Literal[ + "Users", "Administrators", "Engineers", "Purge and Prefetch only (API)", "Purge and Prefetch only (API+Web)" + ] + ] = None + """Group's name.""" + + +class UserDetailed(BaseModel): + id: int + """User's ID.""" + + activated: bool + """Email confirmation: + + - `true` – user confirmed the email; + - `false` – user did not confirm the email. + """ + + auth_types: List[Literal["password", "sso", "github", "google-oauth2"]] + """System field. List of auth types available for the account.""" + + client: float + """User's account ID.""" + + client_and_roles: List[ClientAndRole] + """List of user's clients. User can access to one or more clients.""" + + company: str + """User's company.""" + + deleted: bool + """Deletion flag. If `true` then user was deleted.""" + + email: str + """User's email address.""" + + groups: List[Group] + """User's group in the current account. + + IAM supports 5 groups: + + - Users + - Administrators + - Engineers + - Purge and Prefetch only (API) + - Purge and Prefetch only (API+Web) + """ + + is_active: bool + """User activity flag.""" + + lang: Literal["de", "en", "ru", "zh", "az"] + """User's language. + + Defines language of the control panel and email messages. + """ + + name: Optional[str] = None + """User's name.""" + + phone: Optional[str] = None + """User's phone.""" + + reseller: int + """Services provider ID.""" + + sso_auth: bool + """SSO authentication flag. If `true` then user can login via SAML SSO.""" + + two_fa: bool + """Two-step verification: + + - `true` – user enabled two-step verification; + - `false` – user disabled two-step verification. + """ + + user_type: Literal["common", "reseller", "seller"] + """User's type.""" diff --git a/src/gcore/types/iam/user_invite.py b/src/gcore/types/iam/user_invite.py new file mode 100644 index 00000000..2579f935 --- /dev/null +++ b/src/gcore/types/iam/user_invite.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["UserInvite"] + + +class UserInvite(BaseModel): + status: str + """Status of the invitation.""" + + user_id: int + """Invited user ID.""" diff --git a/src/gcore/types/iam/user_invite_params.py b/src/gcore/types/iam/user_invite_params.py new file mode 100644 index 00000000..47c0baac --- /dev/null +++ b/src/gcore/types/iam/user_invite_params.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["UserInviteParams", "UserRole"] + + +class UserInviteParams(TypedDict, total=False): + client_id: Required[int] + """ID of account.""" + + email: Required[str] + """User email.""" + + user_role: Required[UserRole] + + lang: Literal["de", "en", "ru", "zh", "az"] + """User's language. + + Defines language of the control panel and email messages. + """ + + name: str + """User name.""" + + +class UserRole(TypedDict, total=False): + id: int + """Group's ID: Possible values are: + + - 1 - Administrators* 2 - Users* 5 - Engineers* 3009 - Purge and Prefetch only + (API+Web)* 3022 - Purge and Prefetch only (API) + """ + + name: Literal[ + "Users", "Administrators", "Engineers", "Purge and Prefetch only (API)", "Purge and Prefetch only (API+Web)" + ] + """Group's name.""" diff --git a/src/gcore/types/iam/user_list_params.py b/src/gcore/types/iam/user_list_params.py new file mode 100644 index 00000000..497bb66d --- /dev/null +++ b/src/gcore/types/iam/user_list_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["UserListParams"] + + +class UserListParams(TypedDict, total=False): + limit: int + """The maximum number of items.""" + + offset: int + """Offset relative to the beginning of list.""" diff --git a/src/gcore/types/iam/user_update_params.py b/src/gcore/types/iam/user_update_params.py new file mode 100644 index 00000000..2874ef20 --- /dev/null +++ b/src/gcore/types/iam/user_update_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["UserUpdateParams"] + + +class UserUpdateParams(TypedDict, total=False): + auth_types: Required[List[Literal["password", "sso", "github", "google-oauth2"]]] + """System field. List of auth types available for the account.""" + + email: Required[str] + """User's email address.""" + + lang: Required[Literal["de", "en", "ru", "zh", "az"]] + """User's language. + + Defines language of the control panel and email messages. + """ + + name: Required[Optional[str]] + """User's name.""" + + phone: Required[Optional[str]] + """User's phone.""" diff --git a/src/gcore/types/iam/user_updated.py b/src/gcore/types/iam/user_updated.py new file mode 100644 index 00000000..d3e5c38c --- /dev/null +++ b/src/gcore/types/iam/user_updated.py @@ -0,0 +1,109 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["UserUpdated", "ClientAndRole", "Group"] + + +class ClientAndRole(BaseModel): + client_company_name: str + + client_id: int + + user_id: int + """User's ID.""" + + user_roles: List[str] + """User role in this client.""" + + +class Group(BaseModel): + id: Optional[int] = None + """Group's ID: Possible values are: + + - 1 - Administrators* 2 - Users* 5 - Engineers* 3009 - Purge and Prefetch only + (API+Web)* 3022 - Purge and Prefetch only (API) + """ + + name: Optional[ + Literal[ + "Users", "Administrators", "Engineers", "Purge and Prefetch only (API)", "Purge and Prefetch only (API+Web)" + ] + ] = None + """Group's name.""" + + +class UserUpdated(BaseModel): + id: int + """User's ID.""" + + activated: bool + """Email confirmation: + + - `true` – user confirmed the email; + - `false` – user did not confirm the email. + """ + + auth_types: List[Literal["password", "sso", "github", "google-oauth2"]] + """System field. List of auth types available for the account.""" + + client: float + """User's account ID.""" + + client_and_roles: List[ClientAndRole] + """List of user's clients. User can access to one or more clients.""" + + company: str + """User's company.""" + + deleted: bool + """Deletion flag. If `true` then user was deleted.""" + + email: str + """User's email address.""" + + groups: List[Group] + """User's group in the current account. + + IAM supports 5 groups: + + - Users + - Administrators + - Engineers + - Purge and Prefetch only (API) + - Purge and Prefetch only (API+Web) + """ + + is_active: bool + """User activity flag.""" + + lang: Literal["de", "en", "ru", "zh", "az"] + """User's language. + + Defines language of the control panel and email messages. + """ + + name: Optional[str] = None + """User's name.""" + + phone: Optional[str] = None + """User's phone.""" + + reseller: int + """Services provider ID.""" + + sso_auth: bool + """SSO authentication flag. If `true` then user can login via SAML SSO.""" + + two_fa: bool + """Two-step verification: + + - `true` – user enabled two-step verification; + - `false` – user disabled two-step verification. + """ + + user_type: Literal["common", "reseller", "seller"] + """User's type.""" diff --git a/src/gcore/types/security/__init__.py b/src/gcore/types/security/__init__.py new file mode 100644 index 00000000..4994ea70 --- /dev/null +++ b/src/gcore/types/security/__init__.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .client_view import ClientView as ClientView +from .client_profile import ClientProfile as ClientProfile +from .client_announce import ClientAnnounce as ClientAnnounce +from .event_list_params import EventListParams as EventListParams +from .profile_list_params import ProfileListParams as ProfileListParams +from .profile_create_params import ProfileCreateParams as ProfileCreateParams +from .profile_list_response import ProfileListResponse as ProfileListResponse +from .profile_replace_params import ProfileReplaceParams as ProfileReplaceParams +from .client_profile_template import ClientProfileTemplate as ClientProfileTemplate +from .profile_recreate_params import ProfileRecreateParams as ProfileRecreateParams +from .bgp_announce_list_params import BgpAnnounceListParams as BgpAnnounceListParams +from .bgp_announce_list_response import BgpAnnounceListResponse as BgpAnnounceListResponse +from .bgp_announce_toggle_params import BgpAnnounceToggleParams as BgpAnnounceToggleParams +from .profile_template_list_response import ProfileTemplateListResponse as ProfileTemplateListResponse diff --git a/src/gcore/types/security/bgp_announce_list_params.py b/src/gcore/types/security/bgp_announce_list_params.py new file mode 100644 index 00000000..2bc6a994 --- /dev/null +++ b/src/gcore/types/security/bgp_announce_list_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["BgpAnnounceListParams"] + + +class BgpAnnounceListParams(TypedDict, total=False): + announced: Optional[bool] + + origin: Optional[Literal["STATIC", "DYNAMIC"]] + + site: Optional[str] diff --git a/src/gcore/types/security/bgp_announce_list_response.py b/src/gcore/types/security/bgp_announce_list_response.py new file mode 100644 index 00000000..6981ba90 --- /dev/null +++ b/src/gcore/types/security/bgp_announce_list_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .client_announce import ClientAnnounce + +__all__ = ["BgpAnnounceListResponse"] + +BgpAnnounceListResponse: TypeAlias = List[ClientAnnounce] diff --git a/src/gcore/types/security/bgp_announce_toggle_params.py b/src/gcore/types/security/bgp_announce_toggle_params.py new file mode 100644 index 00000000..4c5dd1b6 --- /dev/null +++ b/src/gcore/types/security/bgp_announce_toggle_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +__all__ = ["BgpAnnounceToggleParams"] + + +class BgpAnnounceToggleParams(TypedDict, total=False): + announce: Required[str] + + enabled: Required[bool] + + client_id: Optional[int] diff --git a/src/gcore/types/security/client_announce.py b/src/gcore/types/security/client_announce.py new file mode 100644 index 00000000..ef276615 --- /dev/null +++ b/src/gcore/types/security/client_announce.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel + +__all__ = ["ClientAnnounce"] + + +class ClientAnnounce(BaseModel): + announced: List[str] + + client_id: int + + not_announced: List[str] diff --git a/src/gcore/types/security/client_profile.py b/src/gcore/types/security/client_profile.py new file mode 100644 index 00000000..7cf11bbb --- /dev/null +++ b/src/gcore/types/security/client_profile.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ..._models import BaseModel +from .client_profile_template import ClientProfileTemplate + +__all__ = ["ClientProfile", "Field", "Options"] + + +class Field(BaseModel): + id: int + + base_field: int + + default: str + + description: str + + field_type: str + + name: str + + required: bool + + validation_schema: Dict[str, object] + + field_value: Optional[object] = None + + +class Options(BaseModel): + active: bool + + bgp: bool + + price: str + + +class ClientProfile(BaseModel): + id: int + + fields: List[Field] + + options: Options + + plan: str + + profile_template: ClientProfileTemplate + + protocols: List[Dict[str, object]] + + site: str + """Region where the protection profiles will be deployed""" + + status: Dict[str, object] + + ip_address: Optional[str] = None diff --git a/src/gcore/types/security/client_profile_template.py b/src/gcore/types/security/client_profile_template.py new file mode 100644 index 00000000..4ea63e14 --- /dev/null +++ b/src/gcore/types/security/client_profile_template.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ClientProfileTemplate", "Field"] + + +class Field(BaseModel): + id: int + + name: str + + default: Optional[str] = None + + description: Optional[str] = None + + field_type: Optional[Literal["int", "bool", "str"]] = None + + required: Optional[bool] = None + + validation_schema: Optional[Dict[str, object]] = None + + +class ClientProfileTemplate(BaseModel): + id: int + + created: datetime + + fields: List[Field] + + name: str + + version: str + + base_template: Optional[int] = None + + description: Optional[str] = None + + template_sifter: Optional[str] = None diff --git a/src/gcore/types/security/client_view.py b/src/gcore/types/security/client_view.py new file mode 100644 index 00000000..802060ab --- /dev/null +++ b/src/gcore/types/security/client_view.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ClientView"] + + +class ClientView(BaseModel): + id: str + + alert_type: Optional[Literal["ddos_alert", "rtbh_alert"]] = None + + attack_power_bps: Optional[float] = None + + attack_power_pps: Optional[float] = None + + attack_start_time: Optional[datetime] = None + + client_id: Optional[int] = None + + notification_type: Optional[str] = None + + number_of_ip_involved_in_attack: Optional[int] = None + + targeted_ip_addresses: Optional[str] = None diff --git a/src/gcore/types/security/event_list_params.py b/src/gcore/types/security/event_list_params.py new file mode 100644 index 00000000..0bd703c3 --- /dev/null +++ b/src/gcore/types/security/event_list_params.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["EventListParams"] + + +class EventListParams(TypedDict, total=False): + alert_type: Optional[Literal["ddos_alert", "rtbh_alert"]] + + date_from: Annotated[Union[Union[str, datetime], str], PropertyInfo(format="iso8601")] + + date_to: Annotated[Union[Union[str, datetime], str], PropertyInfo(format="iso8601")] + + limit: int + + offset: int + + ordering: Literal[ + "attack_start_time", + "-attack_start_time", + "attack_power_bps", + "-attack_power_bps", + "attack_power_pps", + "-attack_power_pps", + "number_of_ip_involved_in_attack", + "-number_of_ip_involved_in_attack", + "alert_type", + "-alert_type", + ] + + targeted_ip_addresses: Optional[str] diff --git a/src/gcore/types/security/profile_create_params.py b/src/gcore/types/security/profile_create_params.py new file mode 100644 index 00000000..a26e0d2a --- /dev/null +++ b/src/gcore/types/security/profile_create_params.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["ProfileCreateParams", "Field"] + + +class ProfileCreateParams(TypedDict, total=False): + fields: Required[Iterable[Field]] + + profile_template: Required[int] + + site: Required[str] + """Region where the protection profiles will be deployed""" + + ip_address: str + """Required for Universal template only. Optional for all others.""" + + +class Field(TypedDict, total=False): + base_field: Required[int] + + field_value: object diff --git a/src/gcore/types/security/profile_list_params.py b/src/gcore/types/security/profile_list_params.py new file mode 100644 index 00000000..e54f232f --- /dev/null +++ b/src/gcore/types/security/profile_list_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ProfileListParams"] + + +class ProfileListParams(TypedDict, total=False): + exclude_empty_address: bool + + include_deleted: bool + + ip_address: str + + site: str diff --git a/src/gcore/types/security/profile_list_response.py b/src/gcore/types/security/profile_list_response.py new file mode 100644 index 00000000..816021c8 --- /dev/null +++ b/src/gcore/types/security/profile_list_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .client_profile import ClientProfile + +__all__ = ["ProfileListResponse"] + +ProfileListResponse: TypeAlias = List[ClientProfile] diff --git a/src/gcore/types/security/profile_recreate_params.py b/src/gcore/types/security/profile_recreate_params.py new file mode 100644 index 00000000..4c6718fe --- /dev/null +++ b/src/gcore/types/security/profile_recreate_params.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["ProfileRecreateParams", "Field"] + + +class ProfileRecreateParams(TypedDict, total=False): + fields: Required[Iterable[Field]] + + profile_template: Required[int] + + ip_address: str + """Required for Universal template only. Optional for all others.""" + + site: str + """Region where the protection profiles will be deployed""" + + +class Field(TypedDict, total=False): + base_field: Required[int] + + field_value: object diff --git a/src/gcore/types/security/profile_replace_params.py b/src/gcore/types/security/profile_replace_params.py new file mode 100644 index 00000000..eb4e5ca8 --- /dev/null +++ b/src/gcore/types/security/profile_replace_params.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["ProfileReplaceParams", "Field"] + + +class ProfileReplaceParams(TypedDict, total=False): + fields: Required[Iterable[Field]] + + profile_template: Required[int] + + ip_address: str + """Required for Universal template only. Optional for all others.""" + + site: str + """Region where the protection profiles will be deployed""" + + +class Field(TypedDict, total=False): + base_field: Required[int] + + field_value: object diff --git a/src/gcore/types/security/profile_template_list_response.py b/src/gcore/types/security/profile_template_list_response.py new file mode 100644 index 00000000..2264e970 --- /dev/null +++ b/src/gcore/types/security/profile_template_list_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .client_profile_template import ClientProfileTemplate + +__all__ = ["ProfileTemplateListResponse"] + +ProfileTemplateListResponse: TypeAlias = List[ClientProfileTemplate] diff --git a/src/gcore/types/storage/__init__.py b/src/gcore/types/storage/__init__.py new file mode 100644 index 00000000..81dc1638 --- /dev/null +++ b/src/gcore/types/storage/__init__.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .bucket import Bucket as Bucket +from .storage import Storage as Storage +from .location import Location as Location +from .usage_total import UsageTotal as UsageTotal +from .usage_series import UsageSeries as UsageSeries +from .bucket_list_params import BucketListParams as BucketListParams +from .storage_list_params import StorageListParams as StorageListParams +from .location_list_params import LocationListParams as LocationListParams +from .storage_create_params import StorageCreateParams as StorageCreateParams +from .storage_update_params import StorageUpdateParams as StorageUpdateParams +from .storage_restore_params import StorageRestoreParams as StorageRestoreParams +from .credential_recreate_params import CredentialRecreateParams as CredentialRecreateParams +from .statistic_get_usage_series_params import StatisticGetUsageSeriesParams as StatisticGetUsageSeriesParams +from .statistic_get_usage_series_response import StatisticGetUsageSeriesResponse as StatisticGetUsageSeriesResponse +from .statistic_get_usage_aggregated_params import ( + StatisticGetUsageAggregatedParams as StatisticGetUsageAggregatedParams, +) diff --git a/src/gcore/types/storage/bucket.py b/src/gcore/types/storage/bucket.py new file mode 100644 index 00000000..f0426088 --- /dev/null +++ b/src/gcore/types/storage/bucket.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["Bucket"] + + +class Bucket(BaseModel): + """BucketDtoV2 for response""" + + name: str + """Name of the S3 bucket""" + + lifecycle: Optional[int] = None + """Lifecycle policy expiration days (zero if not set)""" diff --git a/src/gcore/types/storage/bucket_list_params.py b/src/gcore/types/storage/bucket_list_params.py new file mode 100644 index 00000000..2914e870 --- /dev/null +++ b/src/gcore/types/storage/bucket_list_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["BucketListParams"] + + +class BucketListParams(TypedDict, total=False): + limit: int + """Max number of records in response""" + + offset: int + """Number of records to skip before beginning to write in response.""" diff --git a/src/gcore/types/storage/buckets/__init__.py b/src/gcore/types/storage/buckets/__init__.py new file mode 100644 index 00000000..f8f1f5fb --- /dev/null +++ b/src/gcore/types/storage/buckets/__init__.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .bucket_cors import BucketCors as BucketCors +from .bucket_policy import BucketPolicy as BucketPolicy +from .cor_create_params import CorCreateParams as CorCreateParams +from .policy_get_response import PolicyGetResponse as PolicyGetResponse +from .lifecycle_create_params import LifecycleCreateParams as LifecycleCreateParams diff --git a/src/gcore/types/storage/buckets/bucket_cors.py b/src/gcore/types/storage/buckets/bucket_cors.py new file mode 100644 index 00000000..9e310915 --- /dev/null +++ b/src/gcore/types/storage/buckets/bucket_cors.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel + +__all__ = ["BucketCors"] + + +class BucketCors(BaseModel): + """StorageGetBucketCorsEndpointRes output""" + + allowed_origins: Optional[List[str]] = FieldInfo(alias="allowedOrigins", default=None) + """ + List of allowed origins for Cross-Origin Resource Sharing (CORS) requests. + Contains domains/URLs that are permitted to make cross-origin requests to this + bucket. + """ diff --git a/src/gcore/types/storage/buckets/bucket_policy.py b/src/gcore/types/storage/buckets/bucket_policy.py new file mode 100644 index 00000000..597b80f3 --- /dev/null +++ b/src/gcore/types/storage/buckets/bucket_policy.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import TypeAlias + +__all__ = ["BucketPolicy"] + +BucketPolicy: TypeAlias = bool diff --git a/src/gcore/types/storage/buckets/cor_create_params.py b/src/gcore/types/storage/buckets/cor_create_params.py new file mode 100644 index 00000000..fde3011d --- /dev/null +++ b/src/gcore/types/storage/buckets/cor_create_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ...._types import SequenceNotStr +from ...._utils import PropertyInfo + +__all__ = ["CorCreateParams"] + + +class CorCreateParams(TypedDict, total=False): + storage_id: Required[int] + + allowed_origins: Annotated[SequenceNotStr[str], PropertyInfo(alias="allowedOrigins")] + """List of allowed origins for CORS requests""" diff --git a/src/gcore/types/storage/buckets/lifecycle_create_params.py b/src/gcore/types/storage/buckets/lifecycle_create_params.py new file mode 100644 index 00000000..ca31b5cd --- /dev/null +++ b/src/gcore/types/storage/buckets/lifecycle_create_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["LifecycleCreateParams"] + + +class LifecycleCreateParams(TypedDict, total=False): + storage_id: Required[int] + + expiration_days: int + """ + Number of days after which objects will be automatically deleted from the + bucket. Must be a positive integer. Common values: 30 for monthly cleanup, 365 + for yearly retention. + """ diff --git a/src/gcore/types/storage/buckets/policy_get_response.py b/src/gcore/types/storage/buckets/policy_get_response.py new file mode 100644 index 00000000..c65505ce --- /dev/null +++ b/src/gcore/types/storage/buckets/policy_get_response.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import TypeAlias + +__all__ = ["PolicyGetResponse"] + +PolicyGetResponse: TypeAlias = bool diff --git a/src/gcore/types/storage/credential_recreate_params.py b/src/gcore/types/storage/credential_recreate_params.py new file mode 100644 index 00000000..6ddf0375 --- /dev/null +++ b/src/gcore/types/storage/credential_recreate_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["CredentialRecreateParams"] + + +class CredentialRecreateParams(TypedDict, total=False): + delete_sftp_password: bool + + generate_s3_keys: bool + + generate_sftp_password: bool + + reset_sftp_keys: bool + + sftp_password: str diff --git a/src/gcore/types/storage/location.py b/src/gcore/types/storage/location.py new file mode 100644 index 00000000..5fff1680 --- /dev/null +++ b/src/gcore/types/storage/location.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["Location"] + + +class Location(BaseModel): + """LocationV2 represents location data for v2 API where title is a string""" + + address: str + """Full hostname/address for accessing the storage endpoint in this location""" + + allow_for_new_storage: Literal["deny", "allow"] + """Indicates whether new storage can be created in this location""" + + name: str + """Location code (region identifier)""" + + title: str + """Human-readable title for the location""" + + type: Literal["s3", "sftp"] + """Storage protocol type supported in this location""" diff --git a/src/gcore/types/storage/location_list_params.py b/src/gcore/types/storage/location_list_params.py new file mode 100644 index 00000000..89fa8d59 --- /dev/null +++ b/src/gcore/types/storage/location_list_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["LocationListParams"] + + +class LocationListParams(TypedDict, total=False): + limit: int + + offset: int diff --git a/src/gcore/types/storage/statistic_get_usage_aggregated_params.py b/src/gcore/types/storage/statistic_get_usage_aggregated_params.py new file mode 100644 index 00000000..b57d67a3 --- /dev/null +++ b/src/gcore/types/storage/statistic_get_usage_aggregated_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetUsageAggregatedParams"] + + +class StatisticGetUsageAggregatedParams(TypedDict, total=False): + from_: Annotated[str, PropertyInfo(alias="from")] + """a From date filter""" + + locations: SequenceNotStr[str] + """a Locations list of filter""" + + storages: SequenceNotStr[str] + """a Storages list of filter""" + + to: str + """a To date filter""" diff --git a/src/gcore/types/storage/statistic_get_usage_series_params.py b/src/gcore/types/storage/statistic_get_usage_series_params.py new file mode 100644 index 00000000..860ee30d --- /dev/null +++ b/src/gcore/types/storage/statistic_get_usage_series_params.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetUsageSeriesParams"] + + +class StatisticGetUsageSeriesParams(TypedDict, total=False): + from_: Annotated[str, PropertyInfo(alias="from")] + """a From date filter""" + + granularity: str + """ + a Granularity is period of time for grouping data Valid values are: 1h, 12h, 24h + """ + + locations: SequenceNotStr[str] + """a Locations list of filter""" + + source: int + """a Source is deprecated parameter""" + + storages: SequenceNotStr[str] + """a Storages list of filter""" + + to: str + """a To date filter""" + + ts_string: bool + """ + a TsString is configurator of response time format switch response from unix + time format to RFC3339 (2006-01-02T15:04:05Z07:00) + """ diff --git a/src/gcore/types/storage/statistic_get_usage_series_response.py b/src/gcore/types/storage/statistic_get_usage_series_response.py new file mode 100644 index 00000000..9d5d292e --- /dev/null +++ b/src/gcore/types/storage/statistic_get_usage_series_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel +from .usage_series import UsageSeries + +__all__ = ["StatisticGetUsageSeriesResponse"] + + +class StatisticGetUsageSeriesResponse(BaseModel): + data: Optional[UsageSeries] = None diff --git a/src/gcore/types/storage/storage.py b/src/gcore/types/storage/storage.py new file mode 100644 index 00000000..126b5a7d --- /dev/null +++ b/src/gcore/types/storage/storage.py @@ -0,0 +1,101 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["Storage", "Credentials", "CredentialsKey", "CredentialsS3"] + + +class CredentialsKey(BaseModel): + id: Optional[int] = None + """Unique identifier for the SSH key""" + + created_at: Optional[str] = None + """ISO 8601 timestamp when the SSH key was created""" + + name: Optional[str] = None + """User-defined name for the SSH key""" + + +class CredentialsS3(BaseModel): + access_key: Optional[str] = None + """S3-compatible access key identifier for authentication""" + + secret_key: Optional[str] = None + """S3-compatible secret key for authentication (keep secure)""" + + +class Credentials(BaseModel): + keys: Optional[List[CredentialsKey]] = None + """SSH public keys associated with SFTP storage for passwordless authentication""" + + s3: Optional[CredentialsS3] = None + + sftp_password: Optional[str] = None + """ + Generated or user-provided password for SFTP access (only present for SFTP + storage type) + """ + + +class Storage(BaseModel): + id: int + """Unique identifier for the storage instance""" + + address: str + """Full hostname/address for accessing the storage endpoint""" + + client_id: int + """Client identifier who owns this storage""" + + created_at: str + """ISO 8601 timestamp when the storage was created""" + + location: str + """Geographic location code where the storage is provisioned""" + + name: str + """User-defined name for the storage instance""" + + provisioning_status: Literal["creating", "ok", "updating", "deleting", "deleted"] + """Current provisioning status of the storage instance""" + + reseller_id: int + """Reseller technical client ID associated with the client""" + + type: Literal["sftp", "s3"] + """ + Storage protocol type - either S3-compatible object storage or SFTP file + transfer + """ + + can_restore: Optional[bool] = None + """ + Whether this storage can be restored if deleted (S3 storages only, within 2 + weeks) + """ + + credentials: Optional[Credentials] = None + + custom_config_file: Optional[bool] = None + """Whether custom configuration file is used for this storage""" + + deleted_at: Optional[str] = None + """ + ISO 8601 timestamp when the storage was deleted (only present for deleted + storages) + """ + + disable_http: Optional[bool] = None + """Whether HTTP access is disabled for this storage (HTTPS only)""" + + expires: Optional[str] = None + """ISO 8601 timestamp when the storage will expire (if set)""" + + rewrite_rules: Optional[Dict[str, str]] = None + """Custom URL rewrite rules for the storage (admin-configurable)""" + + server_alias: Optional[str] = None + """Custom domain alias for accessing the storage""" diff --git a/src/gcore/types/storage/storage_create_params.py b/src/gcore/types/storage/storage_create_params.py new file mode 100644 index 00000000..e5582029 --- /dev/null +++ b/src/gcore/types/storage/storage_create_params.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["StorageCreateParams"] + + +class StorageCreateParams(TypedDict, total=False): + location: Required[str] + """Geographic location where the storage will be provisioned. + + Each location represents a specific data center region. + """ + + name: Required[str] + """Unique storage name identifier. + + Must contain only letters, numbers, dashes, and underscores. Cannot be empty and + must be less than 256 characters. + """ + + type: Required[Literal["sftp", "s3"]] + """Storage protocol type. + + Choose 's3' for S3-compatible object storage with API access, or `sftp` for SFTP + file transfer protocol. + """ + + generate_sftp_password: bool + """Automatically generate a secure password for SFTP storage access. + + Only applicable when type is `sftp`. When `true`, a random password will be + generated and returned in the response. + """ + + sftp_password: str + """Custom password for SFTP storage access. + + Only applicable when type is `sftp`. If not provided and + `generate_sftp_password` is `false`, no password authentication will be + available. + """ diff --git a/src/gcore/types/storage/storage_list_params.py b/src/gcore/types/storage/storage_list_params.py new file mode 100644 index 00000000..830c81c9 --- /dev/null +++ b/src/gcore/types/storage/storage_list_params.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["StorageListParams"] + + +class StorageListParams(TypedDict, total=False): + id: str + """Filter by storage ID""" + + limit: int + """Max number of records in response""" + + location: str + """Filter by storage location/region""" + + name: str + """Filter by storage name (exact match)""" + + offset: int + """Number of records to skip before beginning to write in response.""" + + order_by: str + """Field name to sort by""" + + order_direction: Literal["asc", "desc"] + """Ascending or descending order""" + + show_deleted: bool + """Include deleted storages in the response""" + + status: Literal["active", "suspended", "deleted", "pending"] + """Filter by storage status""" + + type: Literal["s3", "sftp"] + """Filter by storage type""" diff --git a/src/gcore/types/storage/storage_restore_params.py b/src/gcore/types/storage/storage_restore_params.py new file mode 100644 index 00000000..632405ec --- /dev/null +++ b/src/gcore/types/storage/storage_restore_params.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["StorageRestoreParams"] + + +class StorageRestoreParams(TypedDict, total=False): + client_id: int diff --git a/src/gcore/types/storage/storage_update_params.py b/src/gcore/types/storage/storage_update_params.py new file mode 100644 index 00000000..c7127a28 --- /dev/null +++ b/src/gcore/types/storage/storage_update_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["StorageUpdateParams"] + + +class StorageUpdateParams(TypedDict, total=False): + expires: str + """ + Duration when the storage should expire in format like "1 years 6 months 2 weeks + 3 days 5 hours 10 minutes 15 seconds". Set empty to remove expiration. + """ + + server_alias: str + """Custom domain alias for accessing the storage. Set empty to remove alias.""" diff --git a/src/gcore/types/storage/usage_series.py b/src/gcore/types/storage/usage_series.py new file mode 100644 index 00000000..dbddf56c --- /dev/null +++ b/src/gcore/types/storage/usage_series.py @@ -0,0 +1,201 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ..._models import BaseModel + +__all__ = ["UsageSeries", "Clients", "ClientsLocations", "ClientsLocationsStorages"] + + +class ClientsLocationsStorages(BaseModel): + buckets_series: Optional[Dict[str, List[List[object]]]] = None + """ + a BucketsSeries is max bucket files count for grouped period + {name:[[timestamp, count]]} + """ + + file_quantity_sum_max: Optional[int] = None + """a FileQuantitySumMax is max sum of files quantity for grouped period""" + + name: Optional[str] = None + """a Name of storage""" + + requests_in_series: Optional[List[List[object]]] = None + """ + a RequestsInSeries is sum of incoming requests for grouped period + [[timestamp, count]] + """ + + requests_in_sum: Optional[int] = None + """a RequestsInSum is sum of incoming requests for grouped period""" + + requests_out_edges_series: Optional[List[List[object]]] = None + """ + a RequestsOutWoEdgesSeries is sum of out requests (only edges) for grouped + period [[timestamp, count]] + """ + + requests_out_edges_sum: Optional[int] = None + """a RequestsOutEdgesSum is sum of out edges requests for grouped period""" + + requests_out_wo_edges_series: Optional[List[List[object]]] = None + """ + a RequestsOutWoEdgesSeries is sum of out requests (without edges) for grouped + period [[timestamp, count]] + """ + + requests_out_wo_edges_sum: Optional[int] = None + """a RequestsOutWoEdgesSum is sum of out no edges requests for grouped period""" + + requests_series: Optional[List[List[object]]] = None + """a RequestsSeries is sum of out requests for grouped period [[timestamp, count]]""" + + requests_sum: Optional[int] = None + """a RequestsSum is sum of all requests for grouped period""" + + size_bytes_hour_series: Optional[List[List[object]]] = None + """ + a SizeBytesHourSeries is value that displays how many bytes were stored per hour + [[timestamp, count]] + """ + + size_max_series: Optional[List[List[object]]] = None + """a SizeMaxSeries is max of files size for grouped period [[timestamp, count]]""" + + size_mean_series: Optional[List[List[object]]] = None + """a SizeMeanSeries is mean of files size for grouped period [[timestamp, count]]""" + + size_sum_bytes_hour: Optional[int] = None + """a SizeSumBytesHour is sum of bytes hour for grouped period""" + + size_sum_max: Optional[int] = None + """a SizeSumMax is max sum of all files sizes for grouped period""" + + size_sum_mean: Optional[int] = None + """a SizeSumMean is mean sum of all files sizes for grouped period""" + + traffic_in_series: Optional[List[List[object]]] = None + """ + a TrafficInSeries is sum of incoming traffic bytes for grouped period + [[timestamp, count]] + """ + + traffic_in_sum: Optional[int] = None + """a TrafficInSum is sum of incoming traffic for grouped period""" + + traffic_out_edges_series: Optional[List[List[object]]] = None + """ + a TrafficOutWoEdgesSeries is sum of out traffic bytes (only edges) for grouped + period [[timestamp, count]] + """ + + traffic_out_edges_sum: Optional[int] = None + """a TrafficOutEdgesSum is sum of out edges traffic for grouped period""" + + traffic_out_wo_edges_series: Optional[List[List[object]]] = None + """ + a TrafficOutWoEdgesSeries is sum of out traffic bytes (without edges) for + grouped period [[timestamp, count]] + """ + + traffic_out_wo_edges_sum: Optional[int] = None + """a TrafficOutWoEdgesSum is sum of out no edges traffic for grouped period""" + + traffic_series: Optional[List[List[object]]] = None + """a TrafficSeries is sum of traffic bytes for grouped period [[timestamp, count]]""" + + traffic_sum: Optional[int] = None + """a TrafficSum is sum of all traffic for grouped period""" + + +class ClientsLocations(BaseModel): + file_quantity_sum_max: Optional[int] = None + """a FileQuantitySumMax is max sum of files quantity for grouped period""" + + name: Optional[str] = None + """a Name of location""" + + requests_in_sum: Optional[int] = None + """a RequestsInSum is sum of incoming requests for grouped period""" + + requests_out_edges_sum: Optional[int] = None + """a RequestsOutEdgesSum is sum of out edges requests for grouped period""" + + requests_out_wo_edges_sum: Optional[int] = None + """a RequestsOutWoEdgesSum is sum of out no edges requests for grouped period""" + + requests_sum: Optional[int] = None + """a RequestsSum is sum of all requests for grouped period""" + + size_sum_bytes_hour: Optional[int] = None + """a SizeSumBytesHour is sum of bytes hour for grouped period""" + + size_sum_max: Optional[int] = None + """a SizeSumMax is max sum of all files sizes for grouped period""" + + size_sum_mean: Optional[int] = None + """a SizeSumMean is mean sum of all files sizes for grouped period""" + + storages: Optional[Dict[str, ClientsLocationsStorages]] = None + """a Storages grouped data""" + + traffic_in_sum: Optional[int] = None + """a TrafficInSum is sum of incoming traffic for grouped period""" + + traffic_out_edges_sum: Optional[int] = None + """a TrafficOutEdgesSum is sum of out edges traffic for grouped period""" + + traffic_out_wo_edges_sum: Optional[int] = None + """a TrafficOutWoEdgesSum is sum of out no edges traffic for grouped period""" + + traffic_sum: Optional[int] = None + """a TrafficSum is sum of all traffic for grouped period""" + + +class Clients(BaseModel): + id: Optional[int] = None + """an ID of client""" + + file_quantity_sum_max: Optional[int] = None + """a FileQuantitySumMax is max sum of files quantity for grouped period""" + + locations: Optional[Dict[str, ClientsLocations]] = None + """a Locations grouped data""" + + requests_in_sum: Optional[int] = None + """a RequestsInSum is sum of incoming requests for grouped period""" + + requests_out_edges_sum: Optional[int] = None + """a RequestsOutEdgesSum is sum of out edges requests for grouped period""" + + requests_out_wo_edges_sum: Optional[int] = None + """a RequestsOutWoEdgesSum is sum of out no edges requests for grouped period""" + + requests_sum: Optional[int] = None + """a RequestsSum is sum of all requests for grouped period""" + + size_sum_bytes_hour: Optional[int] = None + """a SizeSumBytesHour is sum of bytes hour for grouped period""" + + size_sum_max: Optional[int] = None + """a SizeSumMax is max sum of all files sizes for grouped period""" + + size_sum_mean: Optional[int] = None + """a SizeSumMean is mean sum of all files sizes for grouped period""" + + traffic_in_sum: Optional[int] = None + """a TrafficInSum is sum of incoming traffic for grouped period""" + + traffic_out_edges_sum: Optional[int] = None + """a TrafficOutEdgesSum is sum of out edges traffic for grouped period""" + + traffic_out_wo_edges_sum: Optional[int] = None + """a TrafficOutWoEdgesSum is sum of out no edges traffic for grouped period""" + + traffic_sum: Optional[int] = None + """a TrafficSum is sum of all traffic for grouped period""" + + +class UsageSeries(BaseModel): + clients: Optional[Dict[str, Clients]] = None + """a Clients grouped data""" diff --git a/src/gcore/types/storage/usage_total.py b/src/gcore/types/storage/usage_total.py new file mode 100644 index 00000000..6ecfd2ec --- /dev/null +++ b/src/gcore/types/storage/usage_total.py @@ -0,0 +1,56 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["UsageTotal", "Data", "DataMetrics"] + + +class DataMetrics(BaseModel): + file_quantity_sum_max: Optional[int] = None + """a FileQuantitySumMax is max sum of files quantity for grouped period""" + + requests_in_sum: Optional[int] = None + """a RequestsInSum is sum of incoming requests for grouped period""" + + requests_out_edges_sum: Optional[int] = None + """a RequestsOutEdgesSum is sum of out edges requests for grouped period""" + + requests_out_wo_edges_sum: Optional[int] = None + """a RequestsOutWoEdgesSum is sum of out no edges requests for grouped period""" + + requests_sum: Optional[int] = None + """a RequestsSum is sum of all requests for grouped period""" + + size_sum_bytes_hour: Optional[int] = None + """a SizeSumBytesHour is sum of bytes hour for grouped period""" + + size_sum_max: Optional[int] = None + """a SizeSumMax is max sum of all files sizes for grouped period""" + + size_sum_mean: Optional[int] = None + """a SizeSumMean is mean sum of all files sizes for grouped period""" + + traffic_in_sum: Optional[int] = None + """a TrafficInSum is sum of incoming traffic for grouped period""" + + traffic_out_edges_sum: Optional[int] = None + """a TrafficOutEdgesSum is sum of out edges traffic for grouped period""" + + traffic_out_wo_edges_sum: Optional[int] = None + """a TrafficOutWoEdgesSum is sum of out no edges traffic for grouped period""" + + traffic_sum: Optional[int] = None + """a TrafficSum is sum of all traffic for grouped period""" + + +class Data(BaseModel): + """StorageStatsTotalElement for response""" + + metrics: Optional[DataMetrics] = None + + +class UsageTotal(BaseModel): + data: Optional[List[Data]] = None + """StorageUsageTotalRes for response""" diff --git a/src/gcore/types/streaming/__init__.py b/src/gcore/types/streaming/__init__.py new file mode 100644 index 00000000..ab0d0c3c --- /dev/null +++ b/src/gcore/types/streaming/__init__.py @@ -0,0 +1,139 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .clip import Clip as Clip +from .video import Video as Video +from .views import Views as Views +from .player import Player as Player +from .stream import Stream as Stream +from .ai_task import AITask as AITask +from .ffprobes import Ffprobes as Ffprobes +from .playlist import Playlist as Playlist +from .restream import Restream as Restream +from .subtitle import Subtitle as Subtitle +from .broadcast import Broadcast as Broadcast +from .player_param import PlayerParam as PlayerParam +from .quality_sets import QualitySets as QualitySets +from .stream_series import StreamSeries as StreamSeries +from .subtitle_base import SubtitleBase as SubtitleBase +from .views_heatmap import ViewsHeatmap as ViewsHeatmap +from .directory_base import DirectoryBase as DirectoryBase +from .directory_item import DirectoryItem as DirectoryItem +from .playlist_video import PlaylistVideo as PlaylistVideo +from .popular_videos import PopularVideos as PopularVideos +from .storage_series import StorageSeries as StorageSeries +from .unique_viewers import UniqueViewers as UniqueViewers +from .directory_video import DirectoryVideo as DirectoryVideo +from .views_by_region import ViewsByRegion as ViewsByRegion +from .directories_tree import DirectoriesTree as DirectoriesTree +from .playlist_created import PlaylistCreated as PlaylistCreated +from .views_by_browser import ViewsByBrowser as ViewsByBrowser +from .views_by_country import ViewsByCountry as ViewsByCountry +from .views_by_referer import ViewsByReferer as ViewsByReferer +from .max_stream_series import MaxStreamSeries as MaxStreamSeries +from .video_list_params import VideoListParams as VideoListParams +from .views_by_hostname import ViewsByHostname as ViewsByHostname +from .create_video_param import CreateVideoParam as CreateVideoParam +from .player_list_params import PlayerListParams as PlayerListParams +from .stream_list_params import StreamListParams as StreamListParams +from .unique_viewers_cdn import UniqueViewersCDN as UniqueViewersCDN +from .ai_task_list_params import AITaskListParams as AITaskListParams +from .subtitle_base_param import SubtitleBaseParam as SubtitleBaseParam +from .video_create_params import VideoCreateParams as VideoCreateParams +from .video_update_params import VideoUpdateParams as VideoUpdateParams +from .ai_task_get_response import AITaskGetResponse as AITaskGetResponse +from .player_create_params import PlayerCreateParams as PlayerCreateParams +from .player_update_params import PlayerUpdateParams as PlayerUpdateParams +from .playlist_list_params import PlaylistListParams as PlaylistListParams +from .restream_list_params import RestreamListParams as RestreamListParams +from .stream_create_params import StreamCreateParams as StreamCreateParams +from .stream_update_params import StreamUpdateParams as StreamUpdateParams +from .ai_task_create_params import AITaskCreateParams as AITaskCreateParams +from .broadcast_list_params import BroadcastListParams as BroadcastListParams +from .video_create_response import VideoCreateResponse as VideoCreateResponse +from .vod_statistics_series import VodStatisticsSeries as VodStatisticsSeries +from .directory_get_response import DirectoryGetResponse as DirectoryGetResponse +from .playlist_create_params import PlaylistCreateParams as PlaylistCreateParams +from .playlist_update_params import PlaylistUpdateParams as PlaylistUpdateParams +from .restream_create_params import RestreamCreateParams as RestreamCreateParams +from .restream_update_params import RestreamUpdateParams as RestreamUpdateParams +from .ai_task_cancel_response import AITaskCancelResponse as AITaskCancelResponse +from .ai_task_create_response import AITaskCreateResponse as AITaskCreateResponse +from .broadcast_create_params import BroadcastCreateParams as BroadcastCreateParams +from .broadcast_update_params import BroadcastUpdateParams as BroadcastUpdateParams +from .directory_create_params import DirectoryCreateParams as DirectoryCreateParams +from .directory_update_params import DirectoryUpdateParams as DirectoryUpdateParams +from .video_list_names_params import VideoListNamesParams as VideoListNamesParams +from .direct_upload_parameters import DirectUploadParameters as DirectUploadParameters +from .ai_contentmoderation_nsfw import AIContentmoderationNsfw as AIContentmoderationNsfw +from .stream_create_clip_params import StreamCreateClipParams as StreamCreateClipParams +from .views_by_operating_system import ViewsByOperatingSystem as ViewsByOperatingSystem +from .ai_contentmoderation_sport import AIContentmoderationSport as AIContentmoderationSport +from .broadcast_spectators_count import BroadcastSpectatorsCount as BroadcastSpectatorsCount +from .statistic_get_views_params import StatisticGetViewsParams as StatisticGetViewsParams +from .stream_list_clips_response import StreamListClipsResponse as StreamListClipsResponse +from .video_create_multiple_params import VideoCreateMultipleParams as VideoCreateMultipleParams +from .playlist_list_videos_response import PlaylistListVideosResponse as PlaylistListVideosResponse +from .statistic_get_ffprobes_params import StatisticGetFfprobesParams as StatisticGetFfprobesParams +from .ai_task_get_ai_settings_params import AITaskGetAISettingsParams as AITaskGetAISettingsParams +from .quality_set_set_default_params import QualitySetSetDefaultParams as QualitySetSetDefaultParams +from .video_create_multiple_response import VideoCreateMultipleResponse as VideoCreateMultipleResponse +from .ai_contentmoderation_hardnudity import AIContentmoderationHardnudity as AIContentmoderationHardnudity +from .ai_contentmoderation_softnudity import AIContentmoderationSoftnudity as AIContentmoderationSoftnudity +from .stream_start_recording_response import StreamStartRecordingResponse as StreamStartRecordingResponse +from .ai_task_get_ai_settings_response import AITaskGetAISettingsResponse as AITaskGetAISettingsResponse +from .vod_total_stream_duration_series import VodTotalStreamDurationSeries as VodTotalStreamDurationSeries +from .statistic_get_stream_series_params import StatisticGetStreamSeriesParams as StatisticGetStreamSeriesParams +from .statistic_get_views_heatmap_params import StatisticGetViewsHeatmapParams as StatisticGetViewsHeatmapParams +from .statistic_get_popular_videos_params import StatisticGetPopularVideosParams as StatisticGetPopularVideosParams +from .statistic_get_storage_series_params import StatisticGetStorageSeriesParams as StatisticGetStorageSeriesParams +from .statistic_get_unique_viewers_params import StatisticGetUniqueViewersParams as StatisticGetUniqueViewersParams +from .statistic_get_views_by_region_params import StatisticGetViewsByRegionParams as StatisticGetViewsByRegionParams +from .statistic_get_views_by_country_params import StatisticGetViewsByCountryParams as StatisticGetViewsByCountryParams +from .statistic_get_views_by_referer_params import StatisticGetViewsByRefererParams as StatisticGetViewsByRefererParams +from .statistic_get_views_by_browsers_params import ( + StatisticGetViewsByBrowsersParams as StatisticGetViewsByBrowsersParams, +) +from .statistic_get_views_by_hostname_params import ( + StatisticGetViewsByHostnameParams as StatisticGetViewsByHostnameParams, +) +from .statistic_get_max_streams_series_params import ( + StatisticGetMaxStreamsSeriesParams as StatisticGetMaxStreamsSeriesParams, +) +from .statistic_get_unique_viewers_cdn_params import ( + StatisticGetUniqueViewersCDNParams as StatisticGetUniqueViewersCDNParams, +) +from .statistic_get_vod_storage_volume_params import ( + StatisticGetVodStorageVolumeParams as StatisticGetVodStorageVolumeParams, +) +from .statistic_get_vod_watch_time_cdn_params import ( + StatisticGetVodWatchTimeCDNParams as StatisticGetVodWatchTimeCDNParams, +) +from .statistic_get_live_unique_viewers_params import ( + StatisticGetLiveUniqueViewersParams as StatisticGetLiveUniqueViewersParams, +) +from .statistic_get_live_watch_time_cdn_params import ( + StatisticGetLiveWatchTimeCDNParams as StatisticGetLiveWatchTimeCDNParams, +) +from .statistic_get_live_unique_viewers_response import ( + StatisticGetLiveUniqueViewersResponse as StatisticGetLiveUniqueViewersResponse, +) +from .statistic_get_vod_unique_viewers_cdn_params import ( + StatisticGetVodUniqueViewersCDNParams as StatisticGetVodUniqueViewersCDNParams, +) +from .statistic_get_vod_transcoding_duration_params import ( + StatisticGetVodTranscodingDurationParams as StatisticGetVodTranscodingDurationParams, +) +from .statistic_get_vod_watch_time_total_cdn_params import ( + StatisticGetVodWatchTimeTotalCDNParams as StatisticGetVodWatchTimeTotalCDNParams, +) +from .statistic_get_live_watch_time_total_cdn_params import ( + StatisticGetLiveWatchTimeTotalCDNParams as StatisticGetLiveWatchTimeTotalCDNParams, +) +from .statistic_get_views_by_operating_system_params import ( + StatisticGetViewsByOperatingSystemParams as StatisticGetViewsByOperatingSystemParams, +) +from .statistic_get_vod_watch_time_total_cdn_response import ( + StatisticGetVodWatchTimeTotalCDNResponse as StatisticGetVodWatchTimeTotalCDNResponse, +) diff --git a/src/gcore/types/streaming/ai_contentmoderation_hardnudity.py b/src/gcore/types/streaming/ai_contentmoderation_hardnudity.py new file mode 100644 index 00000000..500bc907 --- /dev/null +++ b/src/gcore/types/streaming/ai_contentmoderation_hardnudity.py @@ -0,0 +1,56 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["AIContentmoderationHardnudity"] + + +class AIContentmoderationHardnudity(BaseModel): + category: Literal["hard_nudity", "sport", "nsfw", "soft_nudity"] + """AI content moderation with "hard_nudity" algorithm""" + + task_name: Literal["content-moderation"] + """Name of the task to be performed""" + + url: str + """URL to the MP4 file to analyse. + + File must be publicly accessible via HTTP/HTTPS. + """ + + client_entity_data: Optional[str] = None + """ + Meta parameter, designed to store your own extra information about a video + entity: video source, video id, etc. It is not used in any way in video + processing. + + For example, if an AI-task was created automatically when you uploaded a video + with the AI auto-processing option (nudity detection, etc), then the ID of the + associated video for which the task was performed will be explicitly indicated + here. + """ + + client_user_id: Optional[str] = None + """Meta parameter, designed to store your own identifier. + + Can be used by you to tag requests from different end-users. It is not used in + any way in video processing. + """ + + stop_objects: Optional[ + Literal[ + "ANUS_EXPOSED", + "BUTTOCKS_EXPOSED", + "FEMALE_BREAST_EXPOSED", + "FEMALE_GENITALIA_EXPOSED", + "MALE_BREAST_EXPOSED", + "MALE_GENITALIA_EXPOSED", + ] + ] = None + """ + Comma separated objects, and probabilities, that will cause the processing to + stop immediatelly after finding. + """ diff --git a/src/gcore/types/streaming/ai_contentmoderation_nsfw.py b/src/gcore/types/streaming/ai_contentmoderation_nsfw.py new file mode 100644 index 00000000..fac523f2 --- /dev/null +++ b/src/gcore/types/streaming/ai_contentmoderation_nsfw.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["AIContentmoderationNsfw"] + + +class AIContentmoderationNsfw(BaseModel): + category: Literal["nsfw", "sport", "hard_nudity", "soft_nudity"] + """AI content moderation with NSFW detection algorithm""" + + task_name: Literal["content-moderation"] + """Name of the task to be performed""" + + url: str + """URL to the MP4 file to analyse. + + File must be publicly accessible via HTTP/HTTPS. + """ + + client_entity_data: Optional[str] = None + """ + Meta parameter, designed to store your own extra information about a video + entity: video source, video id, etc. It is not used in any way in video + processing. + + For example, if an AI-task was created automatically when you uploaded a video + with the AI auto-processing option (nudity detection, etc), then the ID of the + associated video for which the task was performed will be explicitly indicated + here. + """ + + client_user_id: Optional[str] = None + """Meta parameter, designed to store your own identifier. + + Can be used by you to tag requests from different end-users. It is not used in + any way in video processing. + """ diff --git a/src/gcore/types/streaming/ai_contentmoderation_softnudity.py b/src/gcore/types/streaming/ai_contentmoderation_softnudity.py new file mode 100644 index 00000000..1fdd19b2 --- /dev/null +++ b/src/gcore/types/streaming/ai_contentmoderation_softnudity.py @@ -0,0 +1,68 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["AIContentmoderationSoftnudity"] + + +class AIContentmoderationSoftnudity(BaseModel): + category: Literal["soft_nudity", "sport", "nsfw", "hard_nudity"] + """AI content moderation with "soft_nudity" algorithm""" + + task_name: Literal["content-moderation"] + """Name of the task to be performed""" + + url: str + """URL to the MP4 file to analyse. + + File must be publicly accessible via HTTP/HTTPS. + """ + + client_entity_data: Optional[str] = None + """ + Meta parameter, designed to store your own extra information about a video + entity: video source, video id, etc. It is not used in any way in video + processing. + + For example, if an AI-task was created automatically when you uploaded a video + with the AI auto-processing option (nudity detection, etc), then the ID of the + associated video for which the task was performed will be explicitly indicated + here. + """ + + client_user_id: Optional[str] = None + """Meta parameter, designed to store your own identifier. + + Can be used by you to tag requests from different end-users. It is not used in + any way in video processing. + """ + + stop_objects: Optional[ + Literal[ + "ANUS_COVERED", + "ANUS_EXPOSED", + "ARMPITS_COVERED", + "ARMPITS_EXPOSED", + "BELLY_COVERED", + "BELLY_EXPOSED", + "BUTTOCKS_COVERED", + "BUTTOCKS_EXPOSED", + "FACE_FEMALE", + "FACE_MALE", + "FEET_COVERED", + "FEET_EXPOSED", + "FEMALE_BREAST_COVERED", + "FEMALE_BREAST_EXPOSED", + "FEMALE_GENITALIA_COVERED", + "FEMALE_GENITALIA_EXPOSED", + "MALE_BREAST_EXPOSED", + "MALE_GENITALIA_EXPOSED", + ] + ] = None + """ + Comma separated objects, and probabilities, that will cause the processing to + stop immediatelly after finding. + """ diff --git a/src/gcore/types/streaming/ai_contentmoderation_sport.py b/src/gcore/types/streaming/ai_contentmoderation_sport.py new file mode 100644 index 00000000..079043dd --- /dev/null +++ b/src/gcore/types/streaming/ai_contentmoderation_sport.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["AIContentmoderationSport"] + + +class AIContentmoderationSport(BaseModel): + category: Literal["sport", "nsfw", "hard_nudity", "soft_nudity"] + """AI content moderation with types of sports activity detection""" + + task_name: Literal["content-moderation"] + """Name of the task to be performed""" + + url: str + """URL to the MP4 file to analyse. + + File must be publicly accessible via HTTP/HTTPS. + """ + + client_entity_data: Optional[str] = None + """ + Meta parameter, designed to store your own extra information about a video + entity: video source, video id, etc. It is not used in any way in video + processing. + + For example, if an AI-task was created automatically when you uploaded a video + with the AI auto-processing option (nudity detection, etc), then the ID of the + associated video for which the task was performed will be explicitly indicated + here. + """ + + client_user_id: Optional[str] = None + """Meta parameter, designed to store your own identifier. + + Can be used by you to tag requests from different end-users. It is not used in + any way in video processing. + """ diff --git a/src/gcore/types/streaming/ai_task.py b/src/gcore/types/streaming/ai_task.py new file mode 100644 index 00000000..7d677e33 --- /dev/null +++ b/src/gcore/types/streaming/ai_task.py @@ -0,0 +1,210 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel +from .ai_contentmoderation_nsfw import AIContentmoderationNsfw +from .ai_contentmoderation_sport import AIContentmoderationSport +from .ai_contentmoderation_hardnudity import AIContentmoderationHardnudity +from .ai_contentmoderation_softnudity import AIContentmoderationSoftnudity + +__all__ = ["AITask", "TaskData", "TaskDataAITranscribe"] + + +class TaskDataAITranscribe(BaseModel): + task_name: Literal["transcription"] + """Name of the task to be performed""" + + url: str + """URL to the MP4 file to analyse. + + File must be publicly accessible via HTTP/HTTPS. + """ + + audio_language: Optional[str] = None + """Language in original audio (transcription only). + + This value is used to determine the language from which to transcribe. + + If this is not set, the system will run auto language identification and the + subtitles will be in the detected language. The method also works based on AI + analysis. It's fairly accurate, but if it's wrong, then set the language + explicitly. + + Additionally, when this is not set, we also support recognition of alternate + languages in the video (language code-switching). + + Language is set by 3-letter language code according to ISO-639-2 (bibliographic + code). + + We can process languages: + + - 'afr': Afrikaans + - 'alb': Albanian + - 'amh': Amharic + - 'ara': Arabic + - 'arm': Armenian + - 'asm': Assamese + - 'aze': Azerbaijani + - 'bak': Bashkir + - 'baq': Basque + - 'bel': Belarusian + - 'ben': Bengali + - 'bos': Bosnian + - 'bre': Breton + - 'bul': Bulgarian + - 'bur': Myanmar + - 'cat': Catalan + - 'chi': Chinese + - 'cze': Czech + - 'dan': Danish + - 'dut': Nynorsk + - 'eng': English + - 'est': Estonian + - 'fao': Faroese + - 'fin': Finnish + - 'fre': French + - 'geo': Georgian + - 'ger': German + - 'glg': Galician + - 'gre': Greek + - 'guj': Gujarati + - 'hat': Haitian creole + - 'hau': Hausa + - 'haw': Hawaiian + - 'heb': Hebrew + - 'hin': Hindi + - 'hrv': Croatian + - 'hun': Hungarian + - 'ice': Icelandic + - 'ind': Indonesian + - 'ita': Italian + - 'jav': Javanese + - 'jpn': Japanese + - 'kan': Kannada + - 'kaz': Kazakh + - 'khm': Khmer + - 'kor': Korean + - 'lao': Lao + - 'lat': Latin + - 'lav': Latvian + - 'lin': Lingala + - 'lit': Lithuanian + - 'ltz': Luxembourgish + - 'mac': Macedonian + - 'mal': Malayalam + - 'mao': Maori + - 'mar': Marathi + - 'may': Malay + - 'mlg': Malagasy + - 'mlt': Maltese + - 'mon': Mongolian + - 'nep': Nepali + - 'dut': Dutch + - 'nor': Norwegian + - 'oci': Occitan + - 'pan': Punjabi + - 'per': Persian + - 'pol': Polish + - 'por': Portuguese + - 'pus': Pashto + - 'rum': Romanian + - 'rus': Russian + - 'san': Sanskrit + - 'sin': Sinhala + - 'slo': Slovak + - 'slv': Slovenian + - 'sna': Shona + - 'snd': Sindhi + - 'som': Somali + - 'spa': Spanish + - 'srp': Serbian + - 'sun': Sundanese + - 'swa': Swahili + - 'swe': Swedish + - 'tam': Tamil + - 'tat': Tatar + - 'tel': Telugu + - 'tgk': Tajik + - 'tgl': Tagalog + - 'tha': Thai + - 'tib': Tibetan + - 'tuk': Turkmen + - 'tur': Turkish + - 'ukr': Ukrainian + - 'urd': Urdu + - 'uzb': Uzbek + - 'vie': Vietnamese + - 'wel': Welsh + - 'yid': Yiddish + - 'yor': Yoruba + """ + + client_entity_data: Optional[str] = None + """ + Meta parameter, designed to store your own extra information about a video + entity: video source, video id, etc. It is not used in any way in video + processing. + + For example, if an AI-task was created automatically when you uploaded a video + with the AI auto-processing option (transcribing, translationing), then the ID + of the associated video for which the task was performed will be explicitly + indicated here. + """ + + client_user_id: Optional[str] = None + """Meta parameter, designed to store your own identifier. + + Can be used by you to tag requests from different end-users. It is not used in + any way in video processing. + """ + + subtitles_language: Optional[str] = None + """ + Indicates which language it is clearly necessary to translate into. If this is + not set, the original language will be used from attribute "audio_language". + + Please note that: + + - transcription into the original language is a free procedure, + - and translation from the original language into any other languages is a + "translation" procedure and is paid. More details in + [POST /streaming/ai/tasks#transcribe](/docs/api-reference/streaming/ai/create-ai-asr-task). + Language is set by 3-letter language code according to ISO-639-2 + (bibliographic code). + """ + + +TaskData: TypeAlias = Union[ + TaskDataAITranscribe, + AIContentmoderationNsfw, + AIContentmoderationHardnudity, + AIContentmoderationSoftnudity, + AIContentmoderationSport, +] + + +class AITask(BaseModel): + progress: Optional[int] = None + """Percentage of task completed. + + A value greater than 0 means that it has been taken into operation and is being + processed. + """ + + status: Optional[Literal["PENDING", "STARTED", "SUCCESS", "FAILURE", "REVOKED", "RETRY"]] = None + """Status of processing the AI task. See GET /ai/results method for description.""" + + task_data: Optional[TaskData] = None + """ + The object will correspond to the task type that was specified in the original + request. There will be one object for transcription, another for searching for + nudity, and so on. + """ + + task_id: Optional[str] = None + """ID of the AI task""" + + task_name: Optional[Literal["content-moderation", "transcription"]] = None + """Type of AI task""" diff --git a/src/gcore/types/streaming/ai_task_cancel_response.py b/src/gcore/types/streaming/ai_task_cancel_response.py new file mode 100644 index 00000000..56197904 --- /dev/null +++ b/src/gcore/types/streaming/ai_task_cancel_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["AITaskCancelResponse"] + + +class AITaskCancelResponse(BaseModel): + result: Optional[str] = None + """A textual explicit description of the result of the operation""" diff --git a/src/gcore/types/streaming/ai_task_create_params.py b/src/gcore/types/streaming/ai_task_create_params.py new file mode 100644 index 00000000..e336f45f --- /dev/null +++ b/src/gcore/types/streaming/ai_task_create_params.py @@ -0,0 +1,177 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AITaskCreateParams"] + + +class AITaskCreateParams(TypedDict, total=False): + task_name: Required[Literal["transcription", "content-moderation"]] + """Name of the task to be performed""" + + url: Required[str] + """URL to the MP4 file to analyse. + + File must be publicly accessible via HTTP/HTTPS. + """ + + audio_language: str + """Language in original audio (transcription only). + + This value is used to determine the language from which to transcribe. + + If this is not set, the system will run auto language identification and the + subtitles will be in the detected language. The method also works based on AI + analysis. It's fairly accurate, but if it's wrong, then set the language + explicitly. + + Additionally, when this is not set, we also support recognition of alternate + languages in the video (language code-switching). + + Language is set by 3-letter language code according to ISO-639-2 (bibliographic + code). + + We can process languages: + + - 'afr': Afrikaans + - 'alb': Albanian + - 'amh': Amharic + - 'ara': Arabic + - 'arm': Armenian + - 'asm': Assamese + - 'aze': Azerbaijani + - 'bak': Bashkir + - 'baq': Basque + - 'bel': Belarusian + - 'ben': Bengali + - 'bos': Bosnian + - 'bre': Breton + - 'bul': Bulgarian + - 'bur': Myanmar + - 'cat': Catalan + - 'chi': Chinese + - 'cze': Czech + - 'dan': Danish + - 'dut': Nynorsk + - 'eng': English + - 'est': Estonian + - 'fao': Faroese + - 'fin': Finnish + - 'fre': French + - 'geo': Georgian + - 'ger': German + - 'glg': Galician + - 'gre': Greek + - 'guj': Gujarati + - 'hat': Haitian creole + - 'hau': Hausa + - 'haw': Hawaiian + - 'heb': Hebrew + - 'hin': Hindi + - 'hrv': Croatian + - 'hun': Hungarian + - 'ice': Icelandic + - 'ind': Indonesian + - 'ita': Italian + - 'jav': Javanese + - 'jpn': Japanese + - 'kan': Kannada + - 'kaz': Kazakh + - 'khm': Khmer + - 'kor': Korean + - 'lao': Lao + - 'lat': Latin + - 'lav': Latvian + - 'lin': Lingala + - 'lit': Lithuanian + - 'ltz': Luxembourgish + - 'mac': Macedonian + - 'mal': Malayalam + - 'mao': Maori + - 'mar': Marathi + - 'may': Malay + - 'mlg': Malagasy + - 'mlt': Maltese + - 'mon': Mongolian + - 'nep': Nepali + - 'dut': Dutch + - 'nor': Norwegian + - 'oci': Occitan + - 'pan': Punjabi + - 'per': Persian + - 'pol': Polish + - 'por': Portuguese + - 'pus': Pashto + - 'rum': Romanian + - 'rus': Russian + - 'san': Sanskrit + - 'sin': Sinhala + - 'slo': Slovak + - 'slv': Slovenian + - 'sna': Shona + - 'snd': Sindhi + - 'som': Somali + - 'spa': Spanish + - 'srp': Serbian + - 'sun': Sundanese + - 'swa': Swahili + - 'swe': Swedish + - 'tam': Tamil + - 'tat': Tatar + - 'tel': Telugu + - 'tgk': Tajik + - 'tgl': Tagalog + - 'tha': Thai + - 'tib': Tibetan + - 'tuk': Turkmen + - 'tur': Turkish + - 'ukr': Ukrainian + - 'urd': Urdu + - 'uzb': Uzbek + - 'vie': Vietnamese + - 'wel': Welsh + - 'yid': Yiddish + - 'yor': Yoruba + """ + + category: Literal["sport", "nsfw", "hard_nudity", "soft_nudity"] + """Model for analysis (content-moderation only). + + Determines what exactly needs to be found in the video. + """ + + client_entity_data: str + """ + Meta parameter, designed to store your own extra information about a video + entity: video source, video id, etc. It is not used in any way in video + processing. + + For example, if an AI-task was created automatically when you uploaded a video + with the AI auto-processing option (nudity detection, etc), then the ID of the + associated video for which the task was performed will be explicitly indicated + here. + """ + + client_user_id: str + """Meta parameter, designed to store your own identifier. + + Can be used by you to tag requests from different end-users. It is not used in + any way in video processing. + """ + + subtitles_language: str + """ + Indicates which language it is clearly necessary to translate into. If this is + not set, the original language will be used from attribute "audio_language". + + Please note that: + + - transcription into the original language is a free procedure, + - and translation from the original language into any other languages is a + "translation" procedure and is paid. More details in + [POST /streaming/ai/tasks#transcribe](/docs/api-reference/streaming/ai/create-ai-asr-task). + Language is set by 3-letter language code according to ISO-639-2 + (bibliographic code). + """ diff --git a/src/gcore/types/streaming/ai_task_create_response.py b/src/gcore/types/streaming/ai_task_create_response.py new file mode 100644 index 00000000..0a6ea96e --- /dev/null +++ b/src/gcore/types/streaming/ai_task_create_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["AITaskCreateResponse"] + + +class AITaskCreateResponse(BaseModel): + task_id: str + """ID of the created AI task, from which you can get the execution result""" diff --git a/src/gcore/types/streaming/ai_task_get_ai_settings_params.py b/src/gcore/types/streaming/ai_task_get_ai_settings_params.py new file mode 100644 index 00000000..f4c0bba3 --- /dev/null +++ b/src/gcore/types/streaming/ai_task_get_ai_settings_params.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AITaskGetAISettingsParams"] + + +class AITaskGetAISettingsParams(TypedDict, total=False): + type: Required[Literal["language_support"]] + """The parameters section for which parameters are requested""" + + audio_language: str + """The source language from which the audio will be transcribed. + + Required when `type=language_support`. Value is 3-letter language code according + to ISO-639-2 (bibliographic code), (e.g., fre for French). + """ + + subtitles_language: str + """The target language the text will be translated into. + + If omitted, the API will return whether the `audio_language` is supported for + transcription only, instead of translation. Value is 3-letter language code + according to ISO-639-2 (bibliographic code), (e.g., fre for French). + """ diff --git a/src/gcore/types/streaming/ai_task_get_ai_settings_response.py b/src/gcore/types/streaming/ai_task_get_ai_settings_response.py new file mode 100644 index 00000000..2476c7f6 --- /dev/null +++ b/src/gcore/types/streaming/ai_task_get_ai_settings_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["AITaskGetAISettingsResponse"] + + +class AITaskGetAISettingsResponse(BaseModel): + supported: Optional[bool] = None + """Is the given language pair supported for transcription and translation?""" diff --git a/src/gcore/types/streaming/ai_task_get_response.py b/src/gcore/types/streaming/ai_task_get_response.py new file mode 100644 index 00000000..293f55c4 --- /dev/null +++ b/src/gcore/types/streaming/ai_task_get_response.py @@ -0,0 +1,268 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from pydantic import Field as FieldInfo + +from .ai_task import AITask +from ..._models import BaseModel + +__all__ = [ + "AITaskGetResponse", + "AITaskGetResponseProcessingTime", + "AITaskGetResponseResult", + "AITaskGetResponseResultAIResultsTranscribe", + "AITaskGetResponseResultAIResultsTranscribeSubtitle", + "AITaskGetResponseResultAIResultsContentmoderationSport", + "AITaskGetResponseResultAIResultsContentmoderationSportFrame", + "AITaskGetResponseResultAIResultsContentmoderationNsfw", + "AITaskGetResponseResultAIResultsContentmoderationNsfwFrame", + "AITaskGetResponseResultAIResultsContentmoderationHardnudity", + "AITaskGetResponseResultAIResultsContentmoderationHardnudityFrame", + "AITaskGetResponseResultAIResultsContentmoderationSoftnudity", + "AITaskGetResponseResultAIResultsContentmoderationSoftnudityFrame", + "AITaskGetResponseResultAIResultsFailure", +] + + +class AITaskGetResponseProcessingTime(BaseModel): + completed_at: Optional[str] = None + """Video processing end time. Format is date time in ISO 8601""" + + started_at: Optional[str] = None + """Video processing start time. Format is date time in ISO 8601""" + + total_time_sec: Optional[float] = None + """Duration of video processing in seconds""" + + +class AITaskGetResponseResultAIResultsTranscribeSubtitle(BaseModel): + end_time: Optional[str] = None + """End time of the phrase, when it ends in the video. Format is "HH:mm:ss.fff".""" + + start_time: Optional[str] = None + """Start time of the phrase when it is heard in the video. + + Format is "HH:mm:ss.fff". + """ + + text: Optional[str] = None + """A complete phrase that sounds during a specified period of time.""" + + +class AITaskGetResponseResultAIResultsTranscribe(BaseModel): + concatenated_text: Optional[str] = None + """Full text of the analyzed video. The value is unstructured, unformatted text.""" + + languages: Optional[List[str]] = None + """An array of language codes that were discovered and/or used in transcription. + + If the audio or subtitle language was explicitly specified in the initial + parameters, it will be copied here. For automatic detection the identified + languages will be displayed here. Also please note that for multilingual audio, + the first 5 languages are displayed in order of frequency of use. + """ + + speech_detected: Optional[bool] = None + """Determines whether speech was detected or not. + + Please note: If the task is in "SUCCESS" status and speech was not found in the + entire file, then "false" will be indicated here and the `subtitles` field will + be empty. + """ + + subtitles: Optional[List[AITaskGetResponseResultAIResultsTranscribeSubtitle]] = None + """An array of phrases divided into time intervals, in the format "json". + + Suitable when you need to display the result in chronometric form, or transfer + the text for further processing. + """ + + vtt_content: Optional[str] = FieldInfo(alias="vttContent", default=None) + """Auto generated subtitles in WebVTT format.""" + + +class AITaskGetResponseResultAIResultsContentmoderationSportFrame(BaseModel): + confidence: Optional[float] = None + """Percentage of probability of identifying the activity""" + + frame_number: Optional[int] = FieldInfo(alias="frame-number", default=None) + """Video frame number where activity was found""" + + label: Optional[str] = None + """Type of detected activity""" + + +class AITaskGetResponseResultAIResultsContentmoderationSport(BaseModel): + detection_results: Optional[ + List[ + Literal[ + "archery", + "arm wrestling", + "playing badminton", + "playing baseball", + "basketball dunk", + "bowling", + "boxing punch", + "boxing speed bag", + "catching or throwing baseball", + "catching or throwing softball", + "cricket", + "curling", + "disc golfing", + "dodgeball", + "fencing", + "football", + "golf chipping", + "golf driving", + "golf putting", + "hitting baseball", + "hockey stop", + "ice skating", + "javelin throw", + "juggling soccer ball", + "kayaking", + "kicking field goal", + "kicking soccer ball", + "playing cricket", + "playing field hockey", + "playing ice hockey", + "playing kickball", + "playing lacrosse", + "playing ping pong", + "playing polo", + "playing squash or racquetball", + "playing tennis", + "playing volleyball", + "pole vault", + "riding a bike", + "riding or walking with horse", + "roller skating", + "rowing", + "sailing", + "shooting goal (soccer)", + "skateboarding", + "skiing", + ] + ] + ] = None + + frames: Optional[List[AITaskGetResponseResultAIResultsContentmoderationSportFrame]] = None + + sport_detected: Optional[bool] = None + """A boolean value whether any sports were detected""" + + +class AITaskGetResponseResultAIResultsContentmoderationNsfwFrame(BaseModel): + confidence: Optional[float] = None + """Percentage of probability of identifying the object""" + + frame_number: Optional[int] = FieldInfo(alias="frame-number", default=None) + """Video frame number where object was found""" + + label: Optional[str] = None + """Type of detected object""" + + +class AITaskGetResponseResultAIResultsContentmoderationNsfw(BaseModel): + detection_results: Optional[List[Literal["nsfw"]]] = None + + frames: Optional[List[AITaskGetResponseResultAIResultsContentmoderationNsfwFrame]] = None + + nsfw_detected: Optional[bool] = None + """A boolean value whether any Not Safe For Work content was detected""" + + +class AITaskGetResponseResultAIResultsContentmoderationHardnudityFrame(BaseModel): + confidence: Optional[float] = None + """Percentage of probability of identifying the object""" + + frame_number: Optional[int] = FieldInfo(alias="frame-number", default=None) + """Video frame number where object was found""" + + label: Optional[str] = None + """Type of detected object""" + + +class AITaskGetResponseResultAIResultsContentmoderationHardnudity(BaseModel): + detection_results: Optional[ + List[ + Literal[ + "ANUS_EXPOSED", + "BUTTOCKS_EXPOSED", + "FEMALE_BREAST_EXPOSED", + "FEMALE_GENITALIA_EXPOSED", + "MALE_BREAST_EXPOSED", + "MALE_GENITALIA_EXPOSED", + ] + ] + ] = None + + frames: Optional[List[AITaskGetResponseResultAIResultsContentmoderationHardnudityFrame]] = None + + porn_detected: Optional[bool] = None + """A boolean value whether any nudity was detected""" + + +class AITaskGetResponseResultAIResultsContentmoderationSoftnudityFrame(BaseModel): + confidence: Optional[float] = None + """Percentage of probability of identifying the object""" + + frame_number: Optional[int] = FieldInfo(alias="frame-number", default=None) + """Video frame number where object was found""" + + label: Optional[str] = None + """Type of detected object""" + + +class AITaskGetResponseResultAIResultsContentmoderationSoftnudity(BaseModel): + detection_results: Optional[ + List[ + Literal[ + "ANUS_COVERED", + "ANUS_EXPOSED", + "ARMPITS_COVERED", + "ARMPITS_EXPOSED", + "BELLY_COVERED", + "BELLY_EXPOSED", + "BUTTOCKS_COVERED", + "BUTTOCKS_EXPOSED", + "FACE_FEMALE", + "FACE_MALE", + "FEET_COVERED", + "FEET_EXPOSED", + "FEMALE_BREAST_COVERED", + "FEMALE_BREAST_EXPOSED", + "FEMALE_GENITALIA_COVERED", + "FEMALE_GENITALIA_EXPOSED", + "MALE_BREAST_EXPOSED", + "MALE_GENITALIA_EXPOSED", + ] + ] + ] = None + + frames: Optional[List[AITaskGetResponseResultAIResultsContentmoderationSoftnudityFrame]] = None + + porn_detected: Optional[bool] = None + """A boolean value whether any nudity and other body part was detected""" + + +class AITaskGetResponseResultAIResultsFailure(BaseModel): + error: str + + +AITaskGetResponseResult: TypeAlias = Union[ + AITaskGetResponseResultAIResultsTranscribe, + AITaskGetResponseResultAIResultsContentmoderationSport, + AITaskGetResponseResultAIResultsContentmoderationNsfw, + AITaskGetResponseResultAIResultsContentmoderationHardnudity, + AITaskGetResponseResultAIResultsContentmoderationSoftnudity, + AITaskGetResponseResultAIResultsFailure, +] + + +class AITaskGetResponse(AITask): + processing_time: Optional[AITaskGetResponseProcessingTime] = None + + result: Optional[AITaskGetResponseResult] = None diff --git a/src/gcore/types/streaming/ai_task_list_params.py b/src/gcore/types/streaming/ai_task_list_params.py new file mode 100644 index 00000000..f449705d --- /dev/null +++ b/src/gcore/types/streaming/ai_task_list_params.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["AITaskListParams"] + + +class AITaskListParams(TypedDict, total=False): + date_created: str + """Time when task was created. Datetime in ISO 8601 format.""" + + limit: int + """Number of results to return per page.""" + + ordering: Literal["task_id", "status", "task_name", "started_at"] + """ + Which field to use when ordering the results: `task_id`, status, and + `task_name`. Sorting is done in ascending (ASC) order. + + If parameter is omitted then "started_at DESC" is used for ordering by default. + """ + + page: int + """Page to view from task list, starting from 1""" + + search: str + """ + This is an field for combined text search in the following fields: `task_id`, + `task_name`, status, and `task_data`. + + Both full and partial searches are possible inside specified above fields. For + example, you can filter tasks of a certain category, or tasks by a specific + original file. + + Example: + + - To filter tasks of Content Moderation NSFW method: + `GET /streaming/ai/tasks?search=nsfw` + - To filter tasks of processing video from a specific origin: + `GET /streaming/ai/tasks?search=s3.eu-west-1.amazonaws.com` + """ + + status: Literal["FAILURE", "PENDING", "RECEIVED", "RETRY", "REVOKED", "STARTED", "SUCCESS"] + """Task status""" + + task_id: str + """The task unique identifier to fiund""" + + task_name: Literal["transcription", "content-moderation"] + """Type of the AI task. + + Reflects the original API method that was used to create the AI task. + """ diff --git a/src/gcore/types/streaming/broadcast.py b/src/gcore/types/streaming/broadcast.py new file mode 100644 index 00000000..b2ba736b --- /dev/null +++ b/src/gcore/types/streaming/broadcast.py @@ -0,0 +1,71 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["Broadcast"] + + +class Broadcast(BaseModel): + name: str + """Broadcast name""" + + ad_id: Optional[int] = None + """ID of ad to be displayed in a live stream. + + If empty the default ad is show. If there is no default ad, no ad is shown + """ + + custom_iframe_url: Optional[str] = None + """Custom URL of iframe for video player to be shared via sharing button in player. + + Auto generated iframe URL is provided by default + """ + + pending_message: Optional[str] = None + """A custom message that is shown if broadcast status is set to pending. + + If empty, a default message is shown + """ + + player_id: Optional[int] = None + """ID of player to be used with a broadcast. If empty the default player is used""" + + poster: Optional[str] = None + """Uploaded poster file""" + + share_url: Optional[str] = None + """ + Custom URL or iframe displayed in the link field when a user clicks on a sharing + button in player. If empty, the link field and social network sharing is + disabled + """ + + show_dvr_after_finish: Optional[bool] = None + """Regulates if a DVR record is shown once a broadcast is finished. + + Has two possible values: + + - **true** — record is shown + - **false** — record isn't shown + + Default is false + """ + + status: Optional[str] = None + """ + Broadcast statuses: + **Pending** — default “Broadcast isn’t started yet” or custom message (see `pending_message` + parameter) is shown, users don't see the live stream + **Live** — broadcast is live, and viewers can see it + **Paused** — “Broadcast is paused” message is shown, users don't see the live stream + + **Finished** — “Broadcast is finished” message is shown, users don't see the + live stream + The users' browsers start displaying the message/stream immediately after you change + the broadcast status + """ + + stream_ids: Optional[List[int]] = None + """IDs of streams used in a broadcast""" diff --git a/src/gcore/types/streaming/broadcast_create_params.py b/src/gcore/types/streaming/broadcast_create_params.py new file mode 100644 index 00000000..eb7da86a --- /dev/null +++ b/src/gcore/types/streaming/broadcast_create_params.py @@ -0,0 +1,76 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["BroadcastCreateParams", "Broadcast"] + + +class BroadcastCreateParams(TypedDict, total=False): + broadcast: Broadcast + + +class Broadcast(TypedDict, total=False): + name: Required[str] + """Broadcast name""" + + ad_id: int + """ID of ad to be displayed in a live stream. + + If empty the default ad is show. If there is no default ad, no ad is shown + """ + + custom_iframe_url: str + """Custom URL of iframe for video player to be shared via sharing button in player. + + Auto generated iframe URL is provided by default + """ + + pending_message: str + """A custom message that is shown if broadcast status is set to pending. + + If empty, a default message is shown + """ + + player_id: int + """ID of player to be used with a broadcast. If empty the default player is used""" + + poster: str + """Uploaded poster file""" + + share_url: str + """ + Custom URL or iframe displayed in the link field when a user clicks on a sharing + button in player. If empty, the link field and social network sharing is + disabled + """ + + show_dvr_after_finish: bool + """Regulates if a DVR record is shown once a broadcast is finished. + + Has two possible values: + + - **true** — record is shown + - **false** — record isn't shown + + Default is false + """ + + status: str + """ + Broadcast statuses: + **Pending** — default “Broadcast isn’t started yet” or custom message (see `pending_message` + parameter) is shown, users don't see the live stream + **Live** — broadcast is live, and viewers can see it + **Paused** — “Broadcast is paused” message is shown, users don't see the live stream + + **Finished** — “Broadcast is finished” message is shown, users don't see the + live stream + The users' browsers start displaying the message/stream immediately after you change + the broadcast status + """ + + stream_ids: Iterable[int] + """IDs of streams used in a broadcast""" diff --git a/src/gcore/types/streaming/broadcast_list_params.py b/src/gcore/types/streaming/broadcast_list_params.py new file mode 100644 index 00000000..d2d93446 --- /dev/null +++ b/src/gcore/types/streaming/broadcast_list_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["BroadcastListParams"] + + +class BroadcastListParams(TypedDict, total=False): + page: int + """Query parameter. Use it to list the paginated content""" diff --git a/src/gcore/types/streaming/broadcast_spectators_count.py b/src/gcore/types/streaming/broadcast_spectators_count.py new file mode 100644 index 00000000..4b26ac98 --- /dev/null +++ b/src/gcore/types/streaming/broadcast_spectators_count.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["BroadcastSpectatorsCount"] + + +class BroadcastSpectatorsCount(BaseModel): + spectators_count: Optional[int] = None + """Number of spectators at the moment""" diff --git a/src/gcore/types/streaming/broadcast_update_params.py b/src/gcore/types/streaming/broadcast_update_params.py new file mode 100644 index 00000000..3b05f518 --- /dev/null +++ b/src/gcore/types/streaming/broadcast_update_params.py @@ -0,0 +1,76 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["BroadcastUpdateParams", "Broadcast"] + + +class BroadcastUpdateParams(TypedDict, total=False): + broadcast: Broadcast + + +class Broadcast(TypedDict, total=False): + name: Required[str] + """Broadcast name""" + + ad_id: int + """ID of ad to be displayed in a live stream. + + If empty the default ad is show. If there is no default ad, no ad is shown + """ + + custom_iframe_url: str + """Custom URL of iframe for video player to be shared via sharing button in player. + + Auto generated iframe URL is provided by default + """ + + pending_message: str + """A custom message that is shown if broadcast status is set to pending. + + If empty, a default message is shown + """ + + player_id: int + """ID of player to be used with a broadcast. If empty the default player is used""" + + poster: str + """Uploaded poster file""" + + share_url: str + """ + Custom URL or iframe displayed in the link field when a user clicks on a sharing + button in player. If empty, the link field and social network sharing is + disabled + """ + + show_dvr_after_finish: bool + """Regulates if a DVR record is shown once a broadcast is finished. + + Has two possible values: + + - **true** — record is shown + - **false** — record isn't shown + + Default is false + """ + + status: str + """ + Broadcast statuses: + **Pending** — default “Broadcast isn’t started yet” or custom message (see `pending_message` + parameter) is shown, users don't see the live stream + **Live** — broadcast is live, and viewers can see it + **Paused** — “Broadcast is paused” message is shown, users don't see the live stream + + **Finished** — “Broadcast is finished” message is shown, users don't see the + live stream + The users' browsers start displaying the message/stream immediately after you change + the broadcast status + """ + + stream_ids: Iterable[int] + """IDs of streams used in a broadcast""" diff --git a/src/gcore/types/streaming/clip.py b/src/gcore/types/streaming/clip.py new file mode 100644 index 00000000..3cab9cc9 --- /dev/null +++ b/src/gcore/types/streaming/clip.py @@ -0,0 +1,90 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["Clip"] + + +class Clip(BaseModel): + id: str + """ID of the clip""" + + duration: int + """Requested segment duration in seconds to be cut. + + Please, note that cutting is based on the idea of instantly creating a clip, + instead of precise timing. So final segment may be: + + - Less than the specified value if there is less data in the DVR than the + requested segment. + - Greater than the specified value, because segment is aligned to the first and + last key frames of already stored fragment in DVR, this way -1 and +1 chunks + can be added to left and right. + + Duration of cutted segment cannot be greater than DVR duration for this stream. + Therefore, to change the maximum, use "dvr_duration" parameter of this stream. + """ + + created_at: Optional[str] = None + """Creation date and time. Format is date time in ISO 8601""" + + expiration: Optional[int] = None + """Expire time of the clip via a public link. + + Unix timestamp in seconds, absolute value. + + This is the time how long the instant clip will be stored in the server memory + and can be accessed via public HLS/MP4 links. Download and/or use the instant + clip before this time expires. + + After the time has expired, the clip is deleted from memory and is no longer + available via the link. You need to create a new segment, or use + `vod_required: true` attribute. + + If value is omitted, then expiration is counted as +3600 seconds (1 hour) to the + end of the clip (i.e. `unix timestamp = + + 3600`). + + Allowed range: 1m <= expiration <= 4h. + + Example: + `24.05.2024 14:00:00 (GMT) + 60 seconds of duration + 3600 seconds of expiration = 24.05.2024 15:01:00 (GMT) is Unix timestamp = 1716562860` + """ + + hls_master: Optional[str] = None + """Link to HLS .m3u8 with immediate clip. + + The link retains same adaptive bitrate as in the stream for end viewers. For + additional restrictions, see the description of parameter "mp4_master". + """ + + mp4_master: Optional[str] = None + """Link to MP4 with immediate clip. + + The link points to max rendition quality. Request of the URL can return: + + - 200 OK – if the clip exists. + - 404 Not found – if the clip did not exist or has already ceased to exist. + - 425 Too early – if recording is on-going now. The file is incomplete and will + be accessible after start+duration time will come. + """ + + renditions: Optional[List[str]] = None + """List of available rendition heights""" + + start: Optional[int] = None + """Starting point of the segment to cut. + + Unix timestamp in seconds, absolute value. Example: + `24.05.2024 14:00:00 (GMT) is Unix timestamp = 1716559200` + + If a value from the past is specified, it is used as the starting point for the + segment to cut. If the value is omitted, then clip will start from now. + """ + + video_id: Optional[int] = None + """ID of the created video if `vod_required`=true""" + + vod_required: Optional[bool] = None + """Indicates if video needs to be stored as VOD""" diff --git a/src/gcore/types/streaming/create_video_param.py b/src/gcore/types/streaming/create_video_param.py new file mode 100644 index 00000000..bb4b74bc --- /dev/null +++ b/src/gcore/types/streaming/create_video_param.py @@ -0,0 +1,247 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["CreateVideoParam"] + + +class CreateVideoParam(TypedDict, total=False): + name: Required[str] + """Video name""" + + auto_transcribe_audio_language: Literal["disable", "auto", ""] + """Automatic creation of subtitles by transcribing the audio track. + + Values: + + - disable – Do not transcribe. + - auto – Automatically detects the activation of the option based on the + settings in your account. If generation is activated, then automatic language + detection while transcribing. + - \\ – Transcribe from specific language. Can be used to specify the exact + language spoken in the audio track, or when auto language detection fails. + Language is set by 3-letter language code according to ISO-639-2 + (bibliographic code). List of languages is available in `audio_language` + attribute of API POST /streaming/ai/transcribe . + + Example: + + ``` + auto_transcribe_audio_language: "auto" + auto_transcribe_audio_language: "ger" + ``` + + More details: + + - List of AI tasks – API + [GET /streaming/ai/tasks](/docs/api-reference/streaming/ai/get-list-of-ai-tasks) + - Add subtitles to an exist video – API + [POST /streaming/videos/{`video_id`}/subtitles](/docs/api-reference/streaming/subtitles/add-subtitle). + """ + + auto_translate_subtitles_language: Literal["disable", "default", ""] + """Automatic translation of auto-transcribed subtitles to the specified + language(s). + + Can be used both together with `auto_transcribe_audio_language` option only. + + Use it when you want to make automatic subtitles in languages other than the + original language in audio. + + Values: + + - disable – Do not translate. + - default – There are 3 default languages: eng,fre,ger + - \\ – Explicit language to translate to, or list of languages separated by a + comma. Look at list of available languages in description of AI ASR task + creation. + + If several languages are specified for translation, a separate subtitle will be + generated for each language. + + Example: + + ``` + auto_translate_subtitles_language: default + auto_translate_subtitles_language: eng,fre,ger + ``` + + Please note that subtitle translation is done separately and after + transcription. Thus separate AI-tasks are created for translation. + """ + + client_user_id: int + """Custom field where you can specify user ID in your system""" + + clip_duration_seconds: int + """ + The length of the trimmed segment to transcode, instead of the entire length of + the video. Is only used in conjunction with specifying the start of a segment. + Transcoding duration is a number in seconds. + """ + + clip_start_seconds: int + """ + If you want to transcode only a trimmed segment of a video instead of entire + length if the video, then you can provide timecodes of starting point and + duration of a segment to process. Start encoding from is a number in seconds. + """ + + custom_iframe_url: str + """Deprecated. + + Custom URL of IFrame for video player to be used in share panel in player. Auto + generated IFrame URL provided by default + """ + + description: str + """Video details; not visible to the end-users""" + + directory_id: int + """ID of the directory where the video should be uploaded. (beta)""" + + origin_http_headers: str + """Authorization HTTP request header. + + Will be used as credentials to authenticate a request to download a file + (specified in "origin_url" parameter) on an external server. + + Syntax: `Authorization: ` + + Examples: + + - "origin_http_headers": "Authorization: Basic ..." + - "origin_http_headers": "Authorization: Bearer ..." + - "origin_http_headers": "Authorization: APIKey ..." Example of usage when + downloading a file from Google Drive: + + ``` + POST https://api.gcore.com/streaming/videos + + "video": { + "name": "IBC 2024 intro.mp4", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "origin_http_headers": "Authorization: Bearer ABC" + } + ``` + """ + + origin_url: str + """ + URL to an original file which you want to copy from external storage. If + specified, system will download the file and will use it as video source for + transcoding. + """ + + poster: str + """Poster is your own static image which can be displayed before the video starts. + + After uploading the video, the system will automatically create several + screenshots (they will be stored in "screenshots" attribute) from which you can + select an default screenshot. This "poster" field is for uploading your own + image. Also use attribute "screenshot_id" to select poster as a default + screnshot. + + Attribute accepts single image as base64-encoded string + [(RFC 2397 – The "data" URL scheme)](https://www.rfc-editor.org/rfc/rfc2397). In + format: `data:[];base64,` + + MIME-types are image/jpeg, image/webp, and image/png and file sizes up to 1Mb. + + Examples: + + - `data:image/jpeg;base64,/9j/4AA...qf/2Q==` + - `data:image/png;base64,iVBORw0KGg...ggg==` + - `data:image/webp;base64,UklGRt.../DgAAAAA` + """ + + priority: int + """ + Priority allows you to adjust the urgency of processing some videos before + others in your account, if your algorithm requires it. For example, when there + are very urgent video and some regular ones that can wait in the queue. + + Value range, integer [-10..10]. -10 is the lowest down-priority, 10 is the + highest up-priority. Default priority is 0. + """ + + projection: str + """Deprecated. + + Regulates the video format: + + - **regular** — plays the video as usual + - **vr360** — plays the video in 360 degree mode + - **vr180** — plays the video in 180 degree mode + - **vr360tb** — plays the video in 3D 360 degree mode Top-Bottom. + + Default is regular + """ + + quality_set_id: int + """ + Custom quality set ID for transcoding, if transcoding is required according to + your conditions. Look at GET /`quality_sets` method + """ + + remote_poster_url: str + """ + Poster URL to download from external resource, instead of uploading via "poster" + attribute. + + It has the same restrictions as "poster" attribute. + """ + + remove_poster: bool + """Set it to true to remove poster""" + + screenshot_id: int + """Default screenshot index. + + Specify an ID from the "screenshots" array, so that the URL of the required + screenshot appears in the "screenshot" attribute as the default screenshot. By + default 5 static screenshots will be taken from different places in the video + after transcoding. If the video is short, there may be fewer screenshots. + + Counting from 0. A value of -1 sets the default screenshot to the URL of your + own image from the "poster" attribute. + + Look at "screenshot" attribute in GET /videos/{`video_id`} for details. + """ + + share_url: str + """Deprecated. + + Custom URL or iframe displayed in the link field when a user clicks on a sharing + button in player. If empty, the link field and social network sharing is + disabled + """ + + source_bitrate_limit: bool + """ + The option allows you to set the video transcoding rule so that the output + bitrate in ABR ladder is not exceeding the bitrate of the original video. + + This option is for advanced users only. + + By default `source_bitrate_limit: true` this option allows you to have the + output bitrate not more than in the original video, thus to transcode video + faster and to deliver it to end-viewers faster as well. At the same time, the + quality will be similar to the original. + + If for some reason you need more byte-space in the output quality when encoding, + you can set this option to `source_bitrate_limit: false`. Then, when + transcoding, the quality ceiling will be raised from the bitrate of the original + video to the maximum possible limit specified in our the Product Documentation. + For example, this may be needed when: + + - to improve the visual quality parameters using PSNR, SSIM, VMAF metrics, + - to improve the picture quality on dynamic scenes, + - etc. + + The option is applied only at the video creation stage and cannot be changed + later. If you want to re-transcode the video using new value, then you need to + create and upload a new video only. + """ diff --git a/src/gcore/types/streaming/direct_upload_parameters.py b/src/gcore/types/streaming/direct_upload_parameters.py new file mode 100644 index 00000000..e0ed5b82 --- /dev/null +++ b/src/gcore/types/streaming/direct_upload_parameters.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["DirectUploadParameters"] + + +class DirectUploadParameters(BaseModel): + token: Optional[str] = None + """Token""" + + servers: Optional[List[object]] = None + """An array which contains information about servers you can upload a video to. + + **Server;** type — object. + + --- + + Server has the following fields: + + - **id;** type — integer + Server ID + - **hostname;** type — string + Server hostname + """ + + video: Optional[object] = None + """Contains information about the created video. + + See the full description in the Get video request + """ diff --git a/src/gcore/types/streaming/directories_tree.py b/src/gcore/types/streaming/directories_tree.py new file mode 100644 index 00000000..54186fc2 --- /dev/null +++ b/src/gcore/types/streaming/directories_tree.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional + +from ..._models import BaseModel +from .directory_base import DirectoryBase + +__all__ = ["DirectoriesTree", "Tree"] + + +class Tree(DirectoryBase): + descendants: Optional[List["DirectoriesTree"]] = None + """Array of subdirectories, if any.""" + + +class DirectoriesTree(BaseModel): + tree: Optional[List[Tree]] = None diff --git a/src/gcore/types/streaming/directory_base.py b/src/gcore/types/streaming/directory_base.py new file mode 100644 index 00000000..7c3372ee --- /dev/null +++ b/src/gcore/types/streaming/directory_base.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["DirectoryBase"] + + +class DirectoryBase(BaseModel): + id: Optional[int] = None + """ID of the directory""" + + created_at: Optional[str] = None + """Time of creation. Datetime in ISO 8601 format.""" + + items_count: Optional[int] = None + """Number of objects in this directory. + + Counting files and folders. The quantity is calculated only at one level (not + recursively in all subfolders). + """ + + name: Optional[str] = None + """Title of the directory""" + + parent_id: Optional[int] = None + """ID of a parent directory. "null" if it's in the root.""" + + updated_at: Optional[str] = None + """Time of last update of the directory entity. Datetime in ISO 8601 format.""" diff --git a/src/gcore/types/streaming/directory_create_params.py b/src/gcore/types/streaming/directory_create_params.py new file mode 100644 index 00000000..76ae7cdf --- /dev/null +++ b/src/gcore/types/streaming/directory_create_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["DirectoryCreateParams"] + + +class DirectoryCreateParams(TypedDict, total=False): + name: Required[str] + """Title of the directory.""" + + parent_id: int + """ID of a parent directory. "null" if it's in the root.""" diff --git a/src/gcore/types/streaming/directory_get_response.py b/src/gcore/types/streaming/directory_get_response.py new file mode 100644 index 00000000..386aede5 --- /dev/null +++ b/src/gcore/types/streaming/directory_get_response.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional + +from ..._models import BaseModel +from .directory_base import DirectoryBase +from .directory_item import DirectoryItem +from .directory_video import DirectoryVideo + +__all__ = ["DirectoryGetResponse", "Directory"] + + +class Directory(DirectoryBase): + items: Optional[List[Union[DirectoryVideo, DirectoryItem]]] = None + """Array of subdirectories, if any.""" + + +class DirectoryGetResponse(BaseModel): + directory: Optional[Directory] = None diff --git a/src/gcore/types/streaming/directory_item.py b/src/gcore/types/streaming/directory_item.py new file mode 100644 index 00000000..1a9d38c7 --- /dev/null +++ b/src/gcore/types/streaming/directory_item.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from .directory_base import DirectoryBase + +__all__ = ["DirectoryItem"] + + +class DirectoryItem(DirectoryBase): + item_type: Optional[Literal["Directory"]] = None + """Type of the entity: directory, or video""" diff --git a/src/gcore/types/streaming/directory_update_params.py b/src/gcore/types/streaming/directory_update_params.py new file mode 100644 index 00000000..2543e2a1 --- /dev/null +++ b/src/gcore/types/streaming/directory_update_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["DirectoryUpdateParams"] + + +class DirectoryUpdateParams(TypedDict, total=False): + name: str + """Title of the directory. Omit this if you don't want to change.""" + + parent_id: int + """ID of a parent directory. + + "null" if it's in the root. Omit this if you don't want to change. + """ diff --git a/src/gcore/types/streaming/directory_video.py b/src/gcore/types/streaming/directory_video.py new file mode 100644 index 00000000..cfc276c9 --- /dev/null +++ b/src/gcore/types/streaming/directory_video.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from .video import Video + +__all__ = ["DirectoryVideo"] + + +class DirectoryVideo(Video): + item_type: Optional[Literal["Video"]] = None + """Type of the entity: directory, or video""" diff --git a/src/gcore/types/streaming/ffprobes.py b/src/gcore/types/streaming/ffprobes.py new file mode 100644 index 00000000..335c99e4 --- /dev/null +++ b/src/gcore/types/streaming/ffprobes.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["Ffprobes", "Data"] + + +class Data(BaseModel): + avg_bitrate: float + + max_fps: float + + max_height: int + + max_keyframe_interval: int + + sum_frames: int + + time: str + + +class Ffprobes(BaseModel): + data: Optional[List[Data]] = None diff --git a/src/gcore/types/streaming/max_stream_series.py b/src/gcore/types/streaming/max_stream_series.py new file mode 100644 index 00000000..bd2166bf --- /dev/null +++ b/src/gcore/types/streaming/max_stream_series.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["MaxStreamSeries", "MaxStreamSeriesItem", "MaxStreamSeriesItemMetrics"] + + +class MaxStreamSeriesItemMetrics(BaseModel): + streams: List[int] + + +class MaxStreamSeriesItem(BaseModel): + client: int + + metrics: MaxStreamSeriesItemMetrics + + +MaxStreamSeries: TypeAlias = List[MaxStreamSeriesItem] diff --git a/src/gcore/types/streaming/player.py b/src/gcore/types/streaming/player.py new file mode 100644 index 00000000..37736297 --- /dev/null +++ b/src/gcore/types/streaming/player.py @@ -0,0 +1,119 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["Player"] + + +class Player(BaseModel): + """Set of properties for displaying videos. + + All parameters may be blank to inherit their values from default Streaming player. + """ + + name: str + """Player name""" + + id: Optional[int] = None + """Player ID""" + + autoplay: Optional[bool] = None + """Enables video playback right after player load: + + - **true** — video starts playing right after player loads + - **false** — video isn’t played automatically. A user must click play to start + + Default is false + """ + + bg_color: Optional[str] = None + """Color of skin background in format #AAAAAA""" + + client_id: Optional[int] = None + """Client ID""" + + custom_css: Optional[str] = None + """Custom CSS to be added to player iframe""" + + design: Optional[str] = None + """String to be rendered as JS parameters to player""" + + disable_skin: Optional[bool] = None + """Enables/Disables player skin: + + - **true** — player skin is disabled + - **false** — player skin is enabled + + Default is false + """ + + fg_color: Optional[str] = None + """Color of skin foreground (elements) in format #AAAAAA""" + + framework: Optional[str] = None + """Player framework type""" + + hover_color: Optional[str] = None + """Color of foreground elements when mouse is over in format #AAAAAA""" + + js_url: Optional[str] = None + """Player main JS file URL. Leave empty to use JS URL from the default player""" + + logo: Optional[str] = None + """URL to logo image""" + + logo_position: Optional[str] = None + """Logotype position. + Has four possible values: + + - **tl** — top left + - **tr** — top right + - **bl** — bottom left + - **br** — bottom right + + Default is null + """ + + mute: Optional[bool] = None + """Regulates the sound volume: + + - **true** — video starts with volume off + - **false** — video starts with volume on + + Default is false + """ + + save_options_to_cookies: Optional[bool] = None + """Enables/Disables saving volume and other options in cookies: + + - **true** — user settings will be saved + - **false** — user settings will not be saved + + Default is true + """ + + show_sharing: Optional[bool] = None + """Enables/Disables sharing button display: + + - **true** — sharing button is displayed + - **false** — no sharing button is displayed + + Default is true + """ + + skin_is_url: Optional[str] = None + """URL to custom skin JS file""" + + speed_control: Optional[bool] = None + """Enables/Disables speed control button display: + + - **true** — sharing button is displayed + - **false** — no sharing button is displayed + + Default is false + """ + + text_color: Optional[str] = None + """Color of skin text elements in format #AAAAAA""" diff --git a/src/gcore/types/streaming/player_create_params.py b/src/gcore/types/streaming/player_create_params.py new file mode 100644 index 00000000..721607bf --- /dev/null +++ b/src/gcore/types/streaming/player_create_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from .player_param import PlayerParam + +__all__ = ["PlayerCreateParams"] + + +class PlayerCreateParams(TypedDict, total=False): + player: PlayerParam + """Set of properties for displaying videos. + + All parameters may be blank to inherit their values from default Streaming + player. + """ diff --git a/src/gcore/types/streaming/player_list_params.py b/src/gcore/types/streaming/player_list_params.py new file mode 100644 index 00000000..82273cc9 --- /dev/null +++ b/src/gcore/types/streaming/player_list_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["PlayerListParams"] + + +class PlayerListParams(TypedDict, total=False): + page: int + """Query parameter. Use it to list the paginated content""" diff --git a/src/gcore/types/streaming/player_param.py b/src/gcore/types/streaming/player_param.py new file mode 100644 index 00000000..accb0aa7 --- /dev/null +++ b/src/gcore/types/streaming/player_param.py @@ -0,0 +1,119 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["PlayerParam"] + + +class PlayerParam(TypedDict, total=False): + """Set of properties for displaying videos. + + All parameters may be blank to inherit their values from default Streaming player. + """ + + name: Required[str] + """Player name""" + + id: int + """Player ID""" + + autoplay: bool + """Enables video playback right after player load: + + - **true** — video starts playing right after player loads + - **false** — video isn’t played automatically. A user must click play to start + + Default is false + """ + + bg_color: str + """Color of skin background in format #AAAAAA""" + + client_id: int + """Client ID""" + + custom_css: str + """Custom CSS to be added to player iframe""" + + design: str + """String to be rendered as JS parameters to player""" + + disable_skin: bool + """Enables/Disables player skin: + + - **true** — player skin is disabled + - **false** — player skin is enabled + + Default is false + """ + + fg_color: str + """Color of skin foreground (elements) in format #AAAAAA""" + + framework: str + """Player framework type""" + + hover_color: str + """Color of foreground elements when mouse is over in format #AAAAAA""" + + js_url: str + """Player main JS file URL. Leave empty to use JS URL from the default player""" + + logo: str + """URL to logo image""" + + logo_position: str + """Logotype position. + Has four possible values: + + - **tl** — top left + - **tr** — top right + - **bl** — bottom left + - **br** — bottom right + + Default is null + """ + + mute: bool + """Regulates the sound volume: + + - **true** — video starts with volume off + - **false** — video starts with volume on + + Default is false + """ + + save_options_to_cookies: bool + """Enables/Disables saving volume and other options in cookies: + + - **true** — user settings will be saved + - **false** — user settings will not be saved + + Default is true + """ + + show_sharing: bool + """Enables/Disables sharing button display: + + - **true** — sharing button is displayed + - **false** — no sharing button is displayed + + Default is true + """ + + skin_is_url: str + """URL to custom skin JS file""" + + speed_control: bool + """Enables/Disables speed control button display: + + - **true** — sharing button is displayed + - **false** — no sharing button is displayed + + Default is false + """ + + text_color: str + """Color of skin text elements in format #AAAAAA""" diff --git a/src/gcore/types/streaming/player_update_params.py b/src/gcore/types/streaming/player_update_params.py new file mode 100644 index 00000000..fb5a12c6 --- /dev/null +++ b/src/gcore/types/streaming/player_update_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from .player_param import PlayerParam + +__all__ = ["PlayerUpdateParams"] + + +class PlayerUpdateParams(TypedDict, total=False): + player: PlayerParam + """Set of properties for displaying videos. + + All parameters may be blank to inherit their values from default Streaming + player. + """ diff --git a/src/gcore/types/streaming/playlist.py b/src/gcore/types/streaming/playlist.py new file mode 100644 index 00000000..e0f94e66 --- /dev/null +++ b/src/gcore/types/streaming/playlist.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["Playlist"] + + +class Playlist(BaseModel): + active: Optional[bool] = None + """Enables/Disables playlist. Has two possible values: + + - true – Playlist can be played. + - false – Playlist is disabled. No broadcast while it's desabled. + """ + + ad_id: Optional[int] = None + """The advertisement ID that will be inserted into the video""" + + client_id: Optional[int] = None + """Current playlist client ID""" + + client_user_id: Optional[int] = None + """Custom field where you can specify user ID in your system""" + + countdown: Optional[bool] = None + """Enables countdown before playlist start with `playlist_type: live`""" + + hls_cmaf_url: Optional[str] = None + """A URL to a master playlist HLS (master-cmaf.m3u8) with CMAF-based chunks. + + Chunks are in fMP4 container. + + It is possible to use the same suffix-options as described in the "hls_url" + attribute. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + """ + + hls_url: Optional[str] = None + """A URL to a master playlist HLS (master.m3u8) with MPEG TS container. + + This URL is a link to the main manifest. But you can also manually specify + suffix-options that will allow you to change the manifest to your request: + + `/playlists/{client_id}_{playlist_id}/master[-cmaf][-min-N][-max-N][-img][-(h264|hevc|av1)].m3u8` + Please see the details in `hls_url` attribute of /videos/{id} method. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + """ + + iframe_url: Optional[str] = None + """A URL to a built-in HTML video player with the video inside. + + It can be inserted into an iframe on your website and the video will + automatically play in all browsers. + + The player can be opened or shared via this direct link. Also the video player + can be integrated into your web pages using the Iframe tag. + + Please see the details in `iframe_url` attribute of /videos/{id} method. + """ + + loop: Optional[bool] = None + """Enables/Disables playlist loop""" + + name: Optional[str] = None + """Playlist name""" + + player_id: Optional[int] = None + """The player ID with which the video will be played""" + + playlist_type: Optional[Literal["live", "vod"]] = None + """Determines whether the playlist: + + - `live` - playlist for live-streaming + - `vod` - playlist is for video on demand access + """ + + start_time: Optional[str] = None + """Playlist start time. + + Playlist won't be available before the specified time. Datetime in ISO 8601 + format. + """ + + video_ids: Optional[List[int]] = None + """A list of VOD IDs included in the playlist. + + Order of videos in a playlist reflects the order of IDs in the array. + + Maximum video limit = 128. + """ diff --git a/src/gcore/types/streaming/playlist_create_params.py b/src/gcore/types/streaming/playlist_create_params.py new file mode 100644 index 00000000..2eebe230 --- /dev/null +++ b/src/gcore/types/streaming/playlist_create_params.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, TypedDict + +__all__ = ["PlaylistCreateParams"] + + +class PlaylistCreateParams(TypedDict, total=False): + active: bool + """Enables/Disables playlist. Has two possible values: + + - true – Playlist can be played. + - false – Playlist is disabled. No broadcast while it's desabled. + """ + + ad_id: int + """The advertisement ID that will be inserted into the video""" + + client_id: int + """Current playlist client ID""" + + client_user_id: int + """Custom field where you can specify user ID in your system""" + + countdown: bool + """Enables countdown before playlist start with `playlist_type: live`""" + + hls_cmaf_url: str + """A URL to a master playlist HLS (master-cmaf.m3u8) with CMAF-based chunks. + + Chunks are in fMP4 container. + + It is possible to use the same suffix-options as described in the "hls_url" + attribute. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + """ + + hls_url: str + """A URL to a master playlist HLS (master.m3u8) with MPEG TS container. + + This URL is a link to the main manifest. But you can also manually specify + suffix-options that will allow you to change the manifest to your request: + + `/playlists/{client_id}_{playlist_id}/master[-cmaf][-min-N][-max-N][-img][-(h264|hevc|av1)].m3u8` + Please see the details in `hls_url` attribute of /videos/{id} method. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + """ + + iframe_url: str + """A URL to a built-in HTML video player with the video inside. + + It can be inserted into an iframe on your website and the video will + automatically play in all browsers. + + The player can be opened or shared via this direct link. Also the video player + can be integrated into your web pages using the Iframe tag. + + Please see the details in `iframe_url` attribute of /videos/{id} method. + """ + + loop: bool + """Enables/Disables playlist loop""" + + name: str + """Playlist name""" + + player_id: int + """The player ID with which the video will be played""" + + playlist_type: Literal["live", "vod"] + """Determines whether the playlist: + + - `live` - playlist for live-streaming + - `vod` - playlist is for video on demand access + """ + + start_time: str + """Playlist start time. + + Playlist won't be available before the specified time. Datetime in ISO 8601 + format. + """ + + video_ids: Iterable[int] + """A list of VOD IDs included in the playlist. + + Order of videos in a playlist reflects the order of IDs in the array. + + Maximum video limit = 128. + """ diff --git a/src/gcore/types/streaming/playlist_created.py b/src/gcore/types/streaming/playlist_created.py new file mode 100644 index 00000000..2f49d6f5 --- /dev/null +++ b/src/gcore/types/streaming/playlist_created.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .playlist import Playlist + +__all__ = ["PlaylistCreated"] + + +class PlaylistCreated(Playlist): + id: Optional[int] = None + """Playlist ID""" diff --git a/src/gcore/types/streaming/playlist_list_params.py b/src/gcore/types/streaming/playlist_list_params.py new file mode 100644 index 00000000..19934578 --- /dev/null +++ b/src/gcore/types/streaming/playlist_list_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["PlaylistListParams"] + + +class PlaylistListParams(TypedDict, total=False): + page: int + """Query parameter. Use it to list the paginated content""" diff --git a/src/gcore/types/streaming/playlist_list_videos_response.py b/src/gcore/types/streaming/playlist_list_videos_response.py new file mode 100644 index 00000000..d8b5bf93 --- /dev/null +++ b/src/gcore/types/streaming/playlist_list_videos_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .playlist_video import PlaylistVideo + +__all__ = ["PlaylistListVideosResponse"] + +PlaylistListVideosResponse: TypeAlias = List[PlaylistVideo] diff --git a/src/gcore/types/streaming/playlist_update_params.py b/src/gcore/types/streaming/playlist_update_params.py new file mode 100644 index 00000000..ce411690 --- /dev/null +++ b/src/gcore/types/streaming/playlist_update_params.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, TypedDict + +__all__ = ["PlaylistUpdateParams"] + + +class PlaylistUpdateParams(TypedDict, total=False): + active: bool + """Enables/Disables playlist. Has two possible values: + + - true – Playlist can be played. + - false – Playlist is disabled. No broadcast while it's desabled. + """ + + ad_id: int + """The advertisement ID that will be inserted into the video""" + + client_id: int + """Current playlist client ID""" + + client_user_id: int + """Custom field where you can specify user ID in your system""" + + countdown: bool + """Enables countdown before playlist start with `playlist_type: live`""" + + hls_cmaf_url: str + """A URL to a master playlist HLS (master-cmaf.m3u8) with CMAF-based chunks. + + Chunks are in fMP4 container. + + It is possible to use the same suffix-options as described in the "hls_url" + attribute. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + """ + + hls_url: str + """A URL to a master playlist HLS (master.m3u8) with MPEG TS container. + + This URL is a link to the main manifest. But you can also manually specify + suffix-options that will allow you to change the manifest to your request: + + `/playlists/{client_id}_{playlist_id}/master[-cmaf][-min-N][-max-N][-img][-(h264|hevc|av1)].m3u8` + Please see the details in `hls_url` attribute of /videos/{id} method. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + """ + + iframe_url: str + """A URL to a built-in HTML video player with the video inside. + + It can be inserted into an iframe on your website and the video will + automatically play in all browsers. + + The player can be opened or shared via this direct link. Also the video player + can be integrated into your web pages using the Iframe tag. + + Please see the details in `iframe_url` attribute of /videos/{id} method. + """ + + loop: bool + """Enables/Disables playlist loop""" + + name: str + """Playlist name""" + + player_id: int + """The player ID with which the video will be played""" + + playlist_type: Literal["live", "vod"] + """Determines whether the playlist: + + - `live` - playlist for live-streaming + - `vod` - playlist is for video on demand access + """ + + start_time: str + """Playlist start time. + + Playlist won't be available before the specified time. Datetime in ISO 8601 + format. + """ + + video_ids: Iterable[int] + """A list of VOD IDs included in the playlist. + + Order of videos in a playlist reflects the order of IDs in the array. + + Maximum video limit = 128. + """ diff --git a/src/gcore/types/streaming/playlist_video.py b/src/gcore/types/streaming/playlist_video.py new file mode 100644 index 00000000..e8762a5e --- /dev/null +++ b/src/gcore/types/streaming/playlist_video.py @@ -0,0 +1,248 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["PlaylistVideo"] + + +class PlaylistVideo(BaseModel): + name: str + """Video name""" + + auto_transcribe_audio_language: Optional[Literal["disable", "auto", ""]] = None + """Automatic creation of subtitles by transcribing the audio track. + + Values: + + - disable – Do not transcribe. + - auto – Automatically detects the activation of the option based on the + settings in your account. If generation is activated, then automatic language + detection while transcribing. + - \\ – Transcribe from specific language. Can be used to specify the exact + language spoken in the audio track, or when auto language detection fails. + Language is set by 3-letter language code according to ISO-639-2 + (bibliographic code). List of languages is available in `audio_language` + attribute of API POST /streaming/ai/transcribe . + + Example: + + ``` + auto_transcribe_audio_language: "auto" + auto_transcribe_audio_language: "ger" + ``` + + More details: + + - List of AI tasks – API + [GET /streaming/ai/tasks](/docs/api-reference/streaming/ai/get-list-of-ai-tasks) + - Add subtitles to an exist video – API + [POST /streaming/videos/{`video_id`}/subtitles](/docs/api-reference/streaming/subtitles/add-subtitle). + """ + + auto_translate_subtitles_language: Optional[Literal["disable", "default", ""]] = None + """Automatic translation of auto-transcribed subtitles to the specified + language(s). + + Can be used both together with `auto_transcribe_audio_language` option only. + + Use it when you want to make automatic subtitles in languages other than the + original language in audio. + + Values: + + - disable – Do not translate. + - default – There are 3 default languages: eng,fre,ger + - \\ – Explicit language to translate to, or list of languages separated by a + comma. Look at list of available languages in description of AI ASR task + creation. + + If several languages are specified for translation, a separate subtitle will be + generated for each language. + + Example: + + ``` + auto_translate_subtitles_language: default + auto_translate_subtitles_language: eng,fre,ger + ``` + + Please note that subtitle translation is done separately and after + transcription. Thus separate AI-tasks are created for translation. + """ + + client_user_id: Optional[int] = None + """Custom field where you can specify user ID in your system""" + + clip_duration_seconds: Optional[int] = None + """ + The length of the trimmed segment to transcode, instead of the entire length of + the video. Is only used in conjunction with specifying the start of a segment. + Transcoding duration is a number in seconds. + """ + + clip_start_seconds: Optional[int] = None + """ + If you want to transcode only a trimmed segment of a video instead of entire + length if the video, then you can provide timecodes of starting point and + duration of a segment to process. Start encoding from is a number in seconds. + """ + + custom_iframe_url: Optional[str] = None + """Deprecated. + + Custom URL of IFrame for video player to be used in share panel in player. Auto + generated IFrame URL provided by default + """ + + description: Optional[str] = None + """Video details; not visible to the end-users""" + + directory_id: Optional[int] = None + """ID of the directory where the video should be uploaded. (beta)""" + + origin_http_headers: Optional[str] = None + """Authorization HTTP request header. + + Will be used as credentials to authenticate a request to download a file + (specified in "origin_url" parameter) on an external server. + + Syntax: `Authorization: ` + + Examples: + + - "origin_http_headers": "Authorization: Basic ..." + - "origin_http_headers": "Authorization: Bearer ..." + - "origin_http_headers": "Authorization: APIKey ..." Example of usage when + downloading a file from Google Drive: + + ``` + POST https://api.gcore.com/streaming/videos + + "video": { + "name": "IBC 2024 intro.mp4", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "origin_http_headers": "Authorization: Bearer ABC" + } + ``` + """ + + origin_url: Optional[str] = None + """ + URL to an original file which you want to copy from external storage. If + specified, system will download the file and will use it as video source for + transcoding. + """ + + poster: Optional[str] = None + """Poster is your own static image which can be displayed before the video starts. + + After uploading the video, the system will automatically create several + screenshots (they will be stored in "screenshots" attribute) from which you can + select an default screenshot. This "poster" field is for uploading your own + image. Also use attribute "screenshot_id" to select poster as a default + screnshot. + + Attribute accepts single image as base64-encoded string + [(RFC 2397 – The "data" URL scheme)](https://www.rfc-editor.org/rfc/rfc2397). In + format: `data:[];base64,` + + MIME-types are image/jpeg, image/webp, and image/png and file sizes up to 1Mb. + + Examples: + + - `data:image/jpeg;base64,/9j/4AA...qf/2Q==` + - `data:image/png;base64,iVBORw0KGg...ggg==` + - `data:image/webp;base64,UklGRt.../DgAAAAA` + """ + + priority: Optional[int] = None + """ + Priority allows you to adjust the urgency of processing some videos before + others in your account, if your algorithm requires it. For example, when there + are very urgent video and some regular ones that can wait in the queue. + + Value range, integer [-10..10]. -10 is the lowest down-priority, 10 is the + highest up-priority. Default priority is 0. + """ + + projection: Optional[str] = None + """Deprecated. + + Regulates the video format: + + - **regular** — plays the video as usual + - **vr360** — plays the video in 360 degree mode + - **vr180** — plays the video in 180 degree mode + - **vr360tb** — plays the video in 3D 360 degree mode Top-Bottom. + + Default is regular + """ + + quality_set_id: Optional[int] = None + """ + Custom quality set ID for transcoding, if transcoding is required according to + your conditions. Look at GET /`quality_sets` method + """ + + remote_poster_url: Optional[str] = None + """ + Poster URL to download from external resource, instead of uploading via "poster" + attribute. + + It has the same restrictions as "poster" attribute. + """ + + remove_poster: Optional[bool] = None + """Set it to true to remove poster""" + + screenshot_id: Optional[int] = None + """Default screenshot index. + + Specify an ID from the "screenshots" array, so that the URL of the required + screenshot appears in the "screenshot" attribute as the default screenshot. By + default 5 static screenshots will be taken from different places in the video + after transcoding. If the video is short, there may be fewer screenshots. + + Counting from 0. A value of -1 sets the default screenshot to the URL of your + own image from the "poster" attribute. + + Look at "screenshot" attribute in GET /videos/{`video_id`} for details. + """ + + share_url: Optional[str] = None + """Deprecated. + + Custom URL or iframe displayed in the link field when a user clicks on a sharing + button in player. If empty, the link field and social network sharing is + disabled + """ + + source_bitrate_limit: Optional[bool] = None + """ + The option allows you to set the video transcoding rule so that the output + bitrate in ABR ladder is not exceeding the bitrate of the original video. + + This option is for advanced users only. + + By default `source_bitrate_limit: true` this option allows you to have the + output bitrate not more than in the original video, thus to transcode video + faster and to deliver it to end-viewers faster as well. At the same time, the + quality will be similar to the original. + + If for some reason you need more byte-space in the output quality when encoding, + you can set this option to `source_bitrate_limit: false`. Then, when + transcoding, the quality ceiling will be raised from the bitrate of the original + video to the maximum possible limit specified in our the Product Documentation. + For example, this may be needed when: + + - to improve the visual quality parameters using PSNR, SSIM, VMAF metrics, + - to improve the picture quality on dynamic scenes, + - etc. + + The option is applied only at the video creation stage and cannot be changed + later. If you want to re-transcode the video using new value, then you need to + create and upload a new video only. + """ diff --git a/src/gcore/types/streaming/popular_videos.py b/src/gcore/types/streaming/popular_videos.py new file mode 100644 index 00000000..ffe42a4b --- /dev/null +++ b/src/gcore/types/streaming/popular_videos.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["PopularVideos", "Data"] + + +class Data(BaseModel): + id: str + + views: int + + +class PopularVideos(BaseModel): + data: Optional[List[Data]] = None diff --git a/src/gcore/types/streaming/quality_set_set_default_params.py b/src/gcore/types/streaming/quality_set_set_default_params.py new file mode 100644 index 00000000..087f75df --- /dev/null +++ b/src/gcore/types/streaming/quality_set_set_default_params.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["QualitySetSetDefaultParams", "Live", "Vod"] + + +class QualitySetSetDefaultParams(TypedDict, total=False): + live: Live + + vod: Vod + + +class Live(TypedDict, total=False): + id: int + """ID of the custom quality set, or "null" for the system default""" + + +class Vod(TypedDict, total=False): + id: int + """ID of the custom quality set, or "null" for the system default""" diff --git a/src/gcore/types/streaming/quality_sets.py b/src/gcore/types/streaming/quality_sets.py new file mode 100644 index 00000000..a39b950b --- /dev/null +++ b/src/gcore/types/streaming/quality_sets.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["QualitySets", "Live", "LiveQuality", "Vod", "VodQuality"] + + +class LiveQuality(BaseModel): + id: Optional[int] = None + """ID of the quality""" + + name: Optional[str] = None + """Name of the quality""" + + +class Live(BaseModel): + id: Optional[int] = None + """ID of the custom quality set""" + + default: Optional[bool] = None + """States if this preset is default for a client profile""" + + name: Optional[str] = None + """Human readable name of the quality set""" + + qualities: Optional[List[LiveQuality]] = None + """Array of associated qualities""" + + +class VodQuality(BaseModel): + id: Optional[int] = None + """ID of the quality""" + + name: Optional[str] = None + """Name of the quality""" + + +class Vod(BaseModel): + id: Optional[int] = None + """ID of the custom quality set""" + + default: Optional[bool] = None + """States if this preset is default for a client profile""" + + name: Optional[str] = None + """Human readable name of the quality set""" + + qualities: Optional[List[VodQuality]] = None + """Array of associated qualities""" + + +class QualitySets(BaseModel): + live: Optional[List[Live]] = None + + vod: Optional[List[Vod]] = None diff --git a/src/gcore/types/streaming/restream.py b/src/gcore/types/streaming/restream.py new file mode 100644 index 00000000..16800b1d --- /dev/null +++ b/src/gcore/types/streaming/restream.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["Restream"] + + +class Restream(BaseModel): + active: Optional[bool] = None + """Enables/Disables restream. Has two possible values: + + - **true** — restream is enabled and can be started + - **false** — restream is disabled. + + Default is true + """ + + client_user_id: Optional[int] = None + """Custom field where you can specify user ID in your system""" + + live: Optional[bool] = None + """Indicates that the stream is being published. Has two possible values: + + - **true** — stream is being published + - **false** — stream isn't published + """ + + name: Optional[str] = None + """Restream name""" + + stream_id: Optional[int] = None + """ID of the stream to restream""" + + uri: Optional[str] = None + """A URL to push the stream to""" diff --git a/src/gcore/types/streaming/restream_create_params.py b/src/gcore/types/streaming/restream_create_params.py new file mode 100644 index 00000000..0d4668e4 --- /dev/null +++ b/src/gcore/types/streaming/restream_create_params.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["RestreamCreateParams", "Restream"] + + +class RestreamCreateParams(TypedDict, total=False): + restream: Restream + + +class Restream(TypedDict, total=False): + active: bool + """Enables/Disables restream. Has two possible values: + + - **true** — restream is enabled and can be started + - **false** — restream is disabled. + + Default is true + """ + + client_user_id: int + """Custom field where you can specify user ID in your system""" + + live: bool + """Indicates that the stream is being published. Has two possible values: + + - **true** — stream is being published + - **false** — stream isn't published + """ + + name: str + """Restream name""" + + stream_id: int + """ID of the stream to restream""" + + uri: str + """A URL to push the stream to""" diff --git a/src/gcore/types/streaming/restream_list_params.py b/src/gcore/types/streaming/restream_list_params.py new file mode 100644 index 00000000..2cc1b34a --- /dev/null +++ b/src/gcore/types/streaming/restream_list_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["RestreamListParams"] + + +class RestreamListParams(TypedDict, total=False): + page: int + """Query parameter. Use it to list the paginated content""" diff --git a/src/gcore/types/streaming/restream_update_params.py b/src/gcore/types/streaming/restream_update_params.py new file mode 100644 index 00000000..9d62d9f7 --- /dev/null +++ b/src/gcore/types/streaming/restream_update_params.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["RestreamUpdateParams", "Restream"] + + +class RestreamUpdateParams(TypedDict, total=False): + restream: Restream + + +class Restream(TypedDict, total=False): + active: bool + """Enables/Disables restream. Has two possible values: + + - **true** — restream is enabled and can be started + - **false** — restream is disabled. + + Default is true + """ + + client_user_id: int + """Custom field where you can specify user ID in your system""" + + live: bool + """Indicates that the stream is being published. Has two possible values: + + - **true** — stream is being published + - **false** — stream isn't published + """ + + name: str + """Restream name""" + + stream_id: int + """ID of the stream to restream""" + + uri: str + """A URL to push the stream to""" diff --git a/src/gcore/types/streaming/statistic_get_ffprobes_params.py b/src/gcore/types/streaming/statistic_get_ffprobes_params.py new file mode 100644 index 00000000..06ab6ea2 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_ffprobes_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["StatisticGetFfprobesParams"] + + +class StatisticGetFfprobesParams(TypedDict, total=False): + date_from: Required[str] + """Start of time frame. Format is ISO 8601.""" + + date_to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" + + stream_id: Required[str] + """Stream ID""" + + interval: int + + units: Literal["second", "minute", "hour", "day", "week", "month"] diff --git a/src/gcore/types/streaming/statistic_get_live_unique_viewers_params.py b/src/gcore/types/streaming/statistic_get_live_unique_viewers_params.py new file mode 100644 index 00000000..76f5fad1 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_live_unique_viewers_params.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetLiveUniqueViewersParams"] + + +class StatisticGetLiveUniqueViewersParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Start of time frame. Format is date time in ISO 8601""" + + to: Required[str] + """End of time frame. Format is date time in ISO 8601""" + + client_user_id: int + """Filter by "client_user_id" """ + + granularity: Literal["1m", "5m", "15m", "1h", "1d"] + """Specifies the time interval for grouping data""" + + stream_id: int + """Filter by "stream_id" """ diff --git a/src/gcore/types/streaming/statistic_get_live_unique_viewers_response.py b/src/gcore/types/streaming/statistic_get_live_unique_viewers_response.py new file mode 100644 index 00000000..c56eb692 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_live_unique_viewers_response.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = [ + "StatisticGetLiveUniqueViewersResponse", + "StatisticGetLiveUniqueViewersResponseItem", + "StatisticGetLiveUniqueViewersResponseItemMetrics", +] + + +class StatisticGetLiveUniqueViewersResponseItemMetrics(BaseModel): + streams: List[int] + + +class StatisticGetLiveUniqueViewersResponseItem(BaseModel): + client: int + + metrics: StatisticGetLiveUniqueViewersResponseItemMetrics + + +StatisticGetLiveUniqueViewersResponse: TypeAlias = List[StatisticGetLiveUniqueViewersResponseItem] diff --git a/src/gcore/types/streaming/statistic_get_live_watch_time_cdn_params.py b/src/gcore/types/streaming/statistic_get_live_watch_time_cdn_params.py new file mode 100644 index 00000000..a1b6a767 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_live_watch_time_cdn_params.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetLiveWatchTimeCDNParams"] + + +class StatisticGetLiveWatchTimeCDNParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Start of the time period for counting minutes of watching. + + Format is date time in ISO 8601. + """ + + client_user_id: int + """Filter by field "client_user_id" """ + + granularity: Literal["1m", "5m", "15m", "1h", "1d", "1mo"] + """Data is grouped by the specified time interval""" + + stream_id: int + """Filter by `stream_id`""" + + to: str + """End of time frame. + + Datetime in ISO 8601 format. If omitted, then the current time is taken + """ diff --git a/src/gcore/types/streaming/statistic_get_live_watch_time_total_cdn_params.py b/src/gcore/types/streaming/statistic_get_live_watch_time_total_cdn_params.py new file mode 100644 index 00000000..1eedab5e --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_live_watch_time_total_cdn_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetLiveWatchTimeTotalCDNParams"] + + +class StatisticGetLiveWatchTimeTotalCDNParams(TypedDict, total=False): + client_user_id: int + """Filter by field "client_user_id" """ + + from_: Annotated[str, PropertyInfo(alias="from")] + """Start of the time period for counting minutes of watching. + + Format is date time in ISO 8601. If omitted, the earliest start time for viewing + is taken + """ + + stream_id: int + """Filter by `stream_id`""" + + to: str + """End of time frame. + + Datetime in ISO 8601 format. If missed, then the current time is taken + """ diff --git a/src/gcore/types/streaming/statistic_get_max_streams_series_params.py b/src/gcore/types/streaming/statistic_get_max_streams_series_params.py new file mode 100644 index 00000000..42040272 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_max_streams_series_params.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetMaxStreamsSeriesParams"] + + +class StatisticGetMaxStreamsSeriesParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Start of time frame. Datetime in ISO 8601 format.""" + + to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" + + granularity: Literal["1m", "5m", "15m", "1h", "1d"] + """specifies the time interval for grouping data""" diff --git a/src/gcore/types/streaming/statistic_get_popular_videos_params.py b/src/gcore/types/streaming/statistic_get_popular_videos_params.py new file mode 100644 index 00000000..9d812241 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_popular_videos_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["StatisticGetPopularVideosParams"] + + +class StatisticGetPopularVideosParams(TypedDict, total=False): + date_from: Required[str] + """Start of time frame. Datetime in ISO 8601 format.""" + + date_to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" diff --git a/src/gcore/types/streaming/statistic_get_storage_series_params.py b/src/gcore/types/streaming/statistic_get_storage_series_params.py new file mode 100644 index 00000000..3e0b8e7b --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_storage_series_params.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetStorageSeriesParams"] + + +class StatisticGetStorageSeriesParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Start of time frame. Datetime in ISO 8601 format.""" + + to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" + + granularity: Literal["1m", "5m", "15m", "1h", "1d"] + """specifies the time interval for grouping data""" diff --git a/src/gcore/types/streaming/statistic_get_stream_series_params.py b/src/gcore/types/streaming/statistic_get_stream_series_params.py new file mode 100644 index 00000000..c2879e08 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_stream_series_params.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetStreamSeriesParams"] + + +class StatisticGetStreamSeriesParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Start of time frame. Datetime in ISO 8601 format.""" + + to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" + + granularity: Literal["1m", "5m", "15m", "1h", "1d"] + """specifies the time interval for grouping data""" diff --git a/src/gcore/types/streaming/statistic_get_unique_viewers_cdn_params.py b/src/gcore/types/streaming/statistic_get_unique_viewers_cdn_params.py new file mode 100644 index 00000000..4944d6da --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_unique_viewers_cdn_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["StatisticGetUniqueViewersCDNParams"] + + +class StatisticGetUniqueViewersCDNParams(TypedDict, total=False): + date_from: Required[str] + """Start of time frame. Format is date time in ISO 8601.""" + + date_to: Required[str] + """End of time frame. Format is date time in ISO 8601.""" + + id: str + """Filter by entity's id. + + Put ID of a Live stream, VOD or a playlist to be calculated. + + If the value is omitted, then the calculation is done for all videos/streams of + the specified type. + + When using this "id" parameter, be sure to specify the "type" parameter too. If + you do not specify a type, the "id" will be ignored. + """ + + type: Literal["live", "vod", "playlist"] + """Filter by entity's type""" diff --git a/src/gcore/types/streaming/statistic_get_unique_viewers_params.py b/src/gcore/types/streaming/statistic_get_unique_viewers_params.py new file mode 100644 index 00000000..4e3f3323 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_unique_viewers_params.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["StatisticGetUniqueViewersParams"] + + +class StatisticGetUniqueViewersParams(TypedDict, total=False): + date_from: Required[str] + """Start of time frame. Datetime in ISO 8601 format.""" + + date_to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" + + id: str + """filter by entity's id""" + + country: str + """filter by country""" + + event: Literal["init", "start", "watch"] + """filter by event's name""" + + group: List[Literal["date", "host", "os", "browser", "platform", "ip", "country", "event", "id"]] + """group=1,2,4 OR group=1&group=2&group=3""" + + host: str + """filter by host""" + + type: Literal["live", "vod", "playlist"] + """filter by entity's type""" diff --git a/src/gcore/types/streaming/statistic_get_views_by_browsers_params.py b/src/gcore/types/streaming/statistic_get_views_by_browsers_params.py new file mode 100644 index 00000000..48ff13e4 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_views_by_browsers_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["StatisticGetViewsByBrowsersParams"] + + +class StatisticGetViewsByBrowsersParams(TypedDict, total=False): + date_from: Required[str] + """Start of time frame. Datetime in ISO 8601 format.""" + + date_to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" diff --git a/src/gcore/types/streaming/statistic_get_views_by_country_params.py b/src/gcore/types/streaming/statistic_get_views_by_country_params.py new file mode 100644 index 00000000..1b5170ff --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_views_by_country_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["StatisticGetViewsByCountryParams"] + + +class StatisticGetViewsByCountryParams(TypedDict, total=False): + date_from: Required[str] + """Start of time frame. Datetime in ISO 8601 format.""" + + date_to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" diff --git a/src/gcore/types/streaming/statistic_get_views_by_hostname_params.py b/src/gcore/types/streaming/statistic_get_views_by_hostname_params.py new file mode 100644 index 00000000..7bd821a1 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_views_by_hostname_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["StatisticGetViewsByHostnameParams"] + + +class StatisticGetViewsByHostnameParams(TypedDict, total=False): + date_from: Required[str] + """Start of time frame. Datetime in ISO 8601 format.""" + + date_to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" diff --git a/src/gcore/types/streaming/statistic_get_views_by_operating_system_params.py b/src/gcore/types/streaming/statistic_get_views_by_operating_system_params.py new file mode 100644 index 00000000..8c7fab23 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_views_by_operating_system_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["StatisticGetViewsByOperatingSystemParams"] + + +class StatisticGetViewsByOperatingSystemParams(TypedDict, total=False): + date_from: Required[str] + """Start of time frame. Datetime in ISO 8601 format.""" + + date_to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" diff --git a/src/gcore/types/streaming/statistic_get_views_by_referer_params.py b/src/gcore/types/streaming/statistic_get_views_by_referer_params.py new file mode 100644 index 00000000..ce5fbd11 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_views_by_referer_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["StatisticGetViewsByRefererParams"] + + +class StatisticGetViewsByRefererParams(TypedDict, total=False): + date_from: Required[str] + """Start of time frame. Datetime in ISO 8601 format.""" + + date_to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" diff --git a/src/gcore/types/streaming/statistic_get_views_by_region_params.py b/src/gcore/types/streaming/statistic_get_views_by_region_params.py new file mode 100644 index 00000000..7cac8462 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_views_by_region_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["StatisticGetViewsByRegionParams"] + + +class StatisticGetViewsByRegionParams(TypedDict, total=False): + date_from: Required[str] + """Start of time frame. Datetime in ISO 8601 format.""" + + date_to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" diff --git a/src/gcore/types/streaming/statistic_get_views_heatmap_params.py b/src/gcore/types/streaming/statistic_get_views_heatmap_params.py new file mode 100644 index 00000000..0c8f3b24 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_views_heatmap_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["StatisticGetViewsHeatmapParams"] + + +class StatisticGetViewsHeatmapParams(TypedDict, total=False): + date_from: Required[str] + """Start of time frame. Datetime in ISO 8601 format.""" + + date_to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" + + stream_id: Required[str] + """video streaming ID""" + + type: Required[Literal["live", "vod", "playlist"]] + """entity's type""" diff --git a/src/gcore/types/streaming/statistic_get_views_params.py b/src/gcore/types/streaming/statistic_get_views_params.py new file mode 100644 index 00000000..fa2f35d6 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_views_params.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["StatisticGetViewsParams"] + + +class StatisticGetViewsParams(TypedDict, total=False): + date_from: Required[str] + """Start of time frame. Datetime in ISO 8601 format.""" + + date_to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" + + id: str + """filter by entity's id""" + + country: str + """filter by country""" + + event: Literal["init", "start", "watch"] + """filter by event's name""" + + group: List[Literal["host", "os", "browser", "platform", "ip", "country", "event", "id"]] + """group=1,2,4 OR group=1&group=2&group=3""" + + host: str + """filter by host""" + + type: Literal["live", "vod", "playlist"] + """filter by entity's type""" diff --git a/src/gcore/types/streaming/statistic_get_vod_storage_volume_params.py b/src/gcore/types/streaming/statistic_get_vod_storage_volume_params.py new file mode 100644 index 00000000..ed6385c9 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_vod_storage_volume_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetVodStorageVolumeParams"] + + +class StatisticGetVodStorageVolumeParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Start of time frame. Datetime in ISO 8601 format.""" + + to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" diff --git a/src/gcore/types/streaming/statistic_get_vod_transcoding_duration_params.py b/src/gcore/types/streaming/statistic_get_vod_transcoding_duration_params.py new file mode 100644 index 00000000..d845157e --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_vod_transcoding_duration_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetVodTranscodingDurationParams"] + + +class StatisticGetVodTranscodingDurationParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Start of time frame. Datetime in ISO 8601 format.""" + + to: Required[str] + """End of time frame. Datetime in ISO 8601 format.""" diff --git a/src/gcore/types/streaming/statistic_get_vod_unique_viewers_cdn_params.py b/src/gcore/types/streaming/statistic_get_vod_unique_viewers_cdn_params.py new file mode 100644 index 00000000..8ad50cc1 --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_vod_unique_viewers_cdn_params.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetVodUniqueViewersCDNParams"] + + +class StatisticGetVodUniqueViewersCDNParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Start of time frame. Format is date time in ISO 8601""" + + to: Required[str] + """End of time frame. Format is date time in ISO 8601""" + + client_user_id: int + """Filter by user "id" """ + + granularity: Literal["1m", "5m", "15m", "1h", "1d"] + """Specifies the time interval for grouping data""" + + slug: str + """Filter by video "slug" """ diff --git a/src/gcore/types/streaming/statistic_get_vod_watch_time_cdn_params.py b/src/gcore/types/streaming/statistic_get_vod_watch_time_cdn_params.py new file mode 100644 index 00000000..7fde051e --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_vod_watch_time_cdn_params.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetVodWatchTimeCDNParams"] + + +class StatisticGetVodWatchTimeCDNParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="from")]] + """Start of the time period for counting minutes of watching. + + Format is date time in ISO 8601. + """ + + client_user_id: int + """Filter by field "client_user_id" """ + + granularity: Literal["1m", "5m", "15m", "1h", "1d", "1mo"] + """Data is grouped by the specified time interval""" + + slug: str + """Filter by video's slug""" + + to: str + """End of time frame. + + Datetime in ISO 8601 format. If omitted, then the current time is taken. + """ diff --git a/src/gcore/types/streaming/statistic_get_vod_watch_time_total_cdn_params.py b/src/gcore/types/streaming/statistic_get_vod_watch_time_total_cdn_params.py new file mode 100644 index 00000000..009ea82e --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_vod_watch_time_total_cdn_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetVodWatchTimeTotalCDNParams"] + + +class StatisticGetVodWatchTimeTotalCDNParams(TypedDict, total=False): + client_user_id: int + """Filter by field "client_user_id" """ + + from_: Annotated[str, PropertyInfo(alias="from")] + """Start of the time period for counting minutes of watching. + + Format is date time in ISO 8601. If omitted, the earliest start time for viewing + is taken + """ + + slug: str + """Filter by video's slug""" + + to: str + """End of time frame. + + Datetime in ISO 8601 format. If omitted, then the current time is taken + """ diff --git a/src/gcore/types/streaming/statistic_get_vod_watch_time_total_cdn_response.py b/src/gcore/types/streaming/statistic_get_vod_watch_time_total_cdn_response.py new file mode 100644 index 00000000..026684ad --- /dev/null +++ b/src/gcore/types/streaming/statistic_get_vod_watch_time_total_cdn_response.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["StatisticGetVodWatchTimeTotalCDNResponse", "StatisticGetVodWatchTimeTotalCDNResponseItem"] + + +class StatisticGetVodWatchTimeTotalCDNResponseItem(BaseModel): + client: int + + duration: int + """count of minutes""" + + client_user_id: Optional[int] = None + + slug: Optional[str] = None + + +StatisticGetVodWatchTimeTotalCDNResponse: TypeAlias = List[StatisticGetVodWatchTimeTotalCDNResponseItem] diff --git a/src/gcore/types/streaming/storage_series.py b/src/gcore/types/streaming/storage_series.py new file mode 100644 index 00000000..34d459e0 --- /dev/null +++ b/src/gcore/types/streaming/storage_series.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["StorageSeries", "StorageSeriesItem", "StorageSeriesItemMetrics"] + + +class StorageSeriesItemMetrics(BaseModel): + max_volume_usage: List[int] + + storage: List[List[int]] + + +class StorageSeriesItem(BaseModel): + client: int + + metrics: StorageSeriesItemMetrics + + +StorageSeries: TypeAlias = List[StorageSeriesItem] diff --git a/src/gcore/types/streaming/stream.py b/src/gcore/types/streaming/stream.py new file mode 100644 index 00000000..e096496b --- /dev/null +++ b/src/gcore/types/streaming/stream.py @@ -0,0 +1,537 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .streams.overlay import Overlay + +__all__ = ["Stream"] + + +class Stream(BaseModel): + name: str + """Stream name. + + Often used as a human-readable name for the stream, but can contain any text you + wish. The values are not unique and may be repeated. + + Examples: + + - Conference in July + - Stream #10003 + - Open-Air Camera #31 Backstage + - 480fd499-2de2-4988-bc1a-a4eebe9818ee + """ + + id: Optional[int] = None + """Stream ID""" + + active: Optional[bool] = None + """Stream switch between on and off. + + This is not an indicator of the status "stream is receiving and it is LIVE", but + rather an on/off switch. + + When stream is switched off, there is no way to process it: PULL is deactivated + and PUSH will return an error. + + - true – stream can be processed + - false – stream is off, and cannot be processed + """ + + auto_record: Optional[bool] = None + """Enables autotomatic recording of the stream when it started. + + So you don't need to call recording manually. + + Result of recording is automatically added to video hosting. For details see the + /streams/`start_recording` method and in knowledge base + + Values: + + - true – auto recording is enabled + - false – auto recording is disabled + """ + + backup_live: Optional[bool] = None + """ + State of receiving and transcoding master stream from source by backup server if + you pushing stream to "backup_push_url" or "backup_push_url_srt". + + Displays the backup server status of PUSH method only. For PULL a "live" field + is always used, even when origin servers are switched using round robin + scheduling (look "uri" field for details). + """ + + backup_push_url: Optional[str] = None + """URL to PUSH master stream to our backup server using RTMP/S protocols. + + Servers for the main and backup streams are distributed geographically. + + Mainly sending one stream to main server is enough. But if you need a backup + stream, then this is the field to PUSH it. + + To use RTMPS just manually change the protocol name from "rtmp://" to + "rtmps://". + + The backup logs are as follows: In PUSH mode, you initiate sending a stream from + your machine. If your stream stops or breaks for some reason and it stops coming + to the main server, then after 3-10 seconds of waiting the stream will turn off + or the backup one will be automatically turned on, if you are pushing it too. + """ + + backup_push_url_srt: Optional[str] = None + """ + URL to PUSH master stream to our backup server using SRT protocol with the same + logic of backup-streams + """ + + broadcast_ids: Optional[List[int]] = None + """IDs of broadcasts which will include this stream""" + + cdn_id: Optional[int] = None + """ + ID of custom CDN resource from which the content will be delivered (only if you + know what you do) + """ + + client_entity_data: Optional[str] = None + """ + Custom meta field designed to store your own extra information about a video + entity: video source, video id, parameters, etc. We do not use this field in any + way when processing the stream. You can store any data in any format (string, + json, etc), saved as a text string. Example: + `client_entity_data = '{ "seq_id": "1234567890", "name": "John Doe", "iat": 1516239022 }'` + """ + + client_user_id: Optional[int] = None + """Custom meta field for storing the Identifier in your system. + + We do not use this field in any way when processing the stream. Example: + `client_user_id = 1001` + """ + + created_at: Optional[str] = None + """Datetime of creation in ISO 8601""" + + dash_url: Optional[str] = None + """MPEG-DASH output. + + URL for transcoded result stream in MPEG-DASH format, with .mpd link. + + Low Latency support: YES. + + This is CMAF-based MPEG-DASH stream. Encoder and packager dynamically assemble + the video stream with fMP4 fragments. Chunks have ±2-4 seconds duration + depending on the settings. All chunks for DASH are transferred through CDN using + chunk transfer technology, which allows to use all the advantages of low latency + delivery of DASH. + + - by default low latency is ±4 sec, because it's stable for almost all last-mile + use cases. + - and its possible to enable ±2 sec for DASH, just ask our Support Team. + + Read more information in the article "How Low Latency streaming works" in the + Knowledge Base. + """ + + dvr_duration: Optional[int] = None + """DVR duration in seconds if DVR feature is enabled for the stream. + + So this is duration of how far the user can rewind the live stream. + + `dvr_duration` range is [30...14400]. + + Maximum value is 4 hours = 14400 seconds. If you need more, ask the Support Team + please. + """ + + dvr_enabled: Optional[bool] = None + """Enables DVR for the stream: + + - true – DVR is enabled + - false – DVR is disabled + """ + + finished_at_primary: Optional[str] = None + """Time when the stream ended for the last time. Datetime in ISO 8601. + + After restarting the stream, this value is not reset to "null", and the time of + the last/previous end is always displayed here. That is, when the start time is + greater than the end time, it means the current session is still ongoing and the + stream has not ended yet. + + If you want to see all information about acitivity of the stream, you can get it + from another method /streaming/statistics/ffprobe. This method shows aggregated + activity parameters during a time, when stream was alive and transcoded. Also + you can create graphs to see the activity. For example + /streaming/statistics/ffprobe?interval=6000&`date_from`=2023-10-01&`date_to`=2023-10-11&`stream_id`=12345 + """ + + frame_rate: Optional[float] = None + """Current FPS of the original stream, if stream is transcoding""" + + hls_cmaf_url: Optional[str] = None + """HLS output. + + URL for transcoded result of stream in HLS CMAF format, with .m3u8 link. + Recommended for use for all HLS streams. + + Low Latency support: YES. + + This is CMAF-based HLS stream. Encoder and packager dynamically assemble the + video stream with fMP4 fragments. Chunks have ±2-4 seconds duration depending on + the settings. All chunks for LL-HLS are transferred through CDN via dividing + into parts (small segments `#EXT-X-PART` of 0.5-1.0 sec duration), which allows + to use all the advantages of low latency delivery of LL-HLS. + + - by default low latency is ±5 sec, because it's stable for almost all last-mile + use cases. + - and its possible to enable ±3 sec for LL-HLS, just ask our Support Team. + + It is also possible to use modifier-attributes, which are described in the + "hls_mpegts_url" field above. If you need to get MPEG-TS (.ts) chunks, look at + the attribute "hls_mpegts_url". + + Read more information in the article "How Low Latency streaming works" in the + Knowledge Base. + """ + + hls_mpegts_endlist_tag: Optional[bool] = None + """ + Add `#EXT-X-ENDLIST` tag within .m3u8 playlist after the last segment of a live + stream when broadcast is ended. + """ + + hls_mpegts_url: Optional[str] = None + """HLS output for legacy devices. + + URL for transcoded result of stream in HLS MPEG-TS (.ts) format, with .m3u8 + link. + + Low Latency support: NO. + + Some legacy devices or software may require MPEG-TS (.ts) segments as a format + for streaming, so we provide this options keeping backward compatibility with + any of your existing workflows. For other cases it's better to use + "hls_cmaf_url" instead. + + You can use this legacy HLSv6 format based on MPEG-TS segmenter in parallel with + main HLS CMAF. Both formats are sharing same segments size, manifest length + (DVR), etc. + + It is also possible to use additional modifier-attributes: + + - ?`get_duration_sec`=true – Adds the real segment duration in seconds to chunk + requests. A chunk duration will be automatically added to a chunk request + string with the "duration_sec" attribute. The value is an integer for a length + multiple of whole seconds, or a fractional number separated by a dot for + chunks that are not multiples of seconds. This attribute allows you to + determine duration in seconds at the level of analyzing the logs of CDN + requests and compare it with file size (so to use it in your analytics). + + Such modifier attributes are applied manually and added to the link obtained + from this field. I.e. `?get_duration_sec=true` + + Example: + `https://demo.gvideo.io/mpegts/2675_19146/master_mpegts.m3u8?get_duration_sec=true` + + ``` + #EXTM3U + #EXT-X-VERSION:6 + #EXT-X-TARGETDURATION:2 + ... + #EXTINF:2.000000, + #EXT-X-PROGRAM-DATE-TIME:2025-08-14T08:15:00 + seg1.ts?duration_sec=2 + ... + ``` + """ + + html_overlay: Optional[bool] = None + """ + Switch on mode to insert and display real-time HTML overlay widgets on top of + live streams + """ + + html_overlays: Optional[List[Overlay]] = None + """Array of HTML overlay widgets""" + + iframe_url: Optional[str] = None + """A URL to a built-in HTML web player with the stream inside. + + It can be inserted into an iframe on your website and the video will + automatically play in all browsers. + + Please, remember that transcoded streams from "hls_cmaf_url" with .m3u8 at the + end, and from "dash_url" with .mpd at the end are to be played inside video + players only. For example: AVplayer on iOS, Exoplayer on Android, HTML web + player in browser, etc. General bowsers like Chrome, Firefox, etc cannot play + transcoded streams with .m3u8 and .mpd at the end. The only exception is Safari, + which can only play Apple's HLS .m3u8 format with limits. + + That's why you may need to use this HTML web player. Please, look Knowledge Base + for details. + + Example of usage on a web page: + + + """ + + live: Optional[bool] = None + """State of receiving and transcoding master stream from source by main server""" + + projection: Optional[Literal["regular", "vr360", "vr180", "vr360tb"]] = None + """ + Visualization mode for 360° streams, how the stream is rendered in our web + player ONLY. If you would like to show video 360° in an external video player, + then use parameters of that video player. + + Modes: + + - regular – regular “flat” stream + - vr360 – display stream in 360° mode + - vr180 – display stream in 180° mode + - vr360tb – display stream in 3D 360° mode Top-Bottom + """ + + pull: Optional[bool] = None + """Indicates if stream is pulled from external server or not. + + Has two possible values: + + - true – stream is received by PULL method. Use this when need to get stream + from external server. + - false – stream is received by PUSH method. Use this when need to send stream + from end-device to our Streaming Platform, i.e. from your encoder, mobile app + or OBS Studio. + """ + + push_url: Optional[str] = None + """URL to PUSH master stream to our main server using RTMP and RTMPS protocols. + + To use RTMPS just manually change the protocol name from "rtmp://" to + "rtmps://". + + Use only 1 protocol of sending a master stream: eitheronly RTMP/S (`push_url`), + or only SRT (`push_url_srt`). + + If you see an error like "invalid SSL certificate" try the following: + + - Make sure the push URL is correct, and it contains "rtmps://". + - If the URL looks correct but you still get an SSL error, try specifying the + port 443 in the URL. Here’s an example: + rtmps://vp-push.domain.com:443/in/stream?key. + - If you're still having trouble, then your encoder may not support RTMPS. + Double-check the documentation for your encoder. + + Please note that 1 connection and 1 protocol can be used at a single moment in + time per unique stream key input. Trying to send 2+ connection requests into the + single `push_url`, or 2+ protocols at once will not lead to a result. + + For example, transcoding process will fail if: + + - you are pushing primary and backup RTMP to the same single `push_url` + simultaneously + - you are pushing RTMP to `push_url` and SRT to `push_url_srt` simultaneously + + For advanced customers only: For your complexly distributed broadcast systems, + it is also possible to additionally output an array of multi-regional ingestion + points for manual selection from them. To activate this mode, contact your + manager or the Support Team to activate the "multi_region_push_urls" attibute. + But if you clearly don’t understand why you need this, then it’s best to use the + default single URL in the "push_url" attribute. + """ + + push_url_srt: Optional[str] = None + """URL to PUSH master stream to our main server using SRT protocol. + + Use only 1 protocol of sending a master stream: eitheronly RTMP/S (`push_url`), + or only SRT (`push_url_srt`). + + **Setup SRT latency on your sender side** + + SRT is designed as a low-latency transport protocol, but real networks are not + always stable and in some cases the end-to-end path from the venue to the ingest + point can be long. For this reason, it is important to configure the latency + parameter carefully to match the actual network conditions. + + Small latency values may lead to packet loss when jitter or retransmissions + occur, while very large values introduce unnecessary end-to-end delay. + + _Incorrect or low default value is one of the most common reasons for packet + loss, frames loss, and bad picture._ + + We therefore recommend setting latency manually rather than relying on the + default, to ensure the buffer is correctly sized for your environment. A + practical range is 400–2000 ms, with the exact value chosen based on RTT, + jitter, and expected packet loss. + + Be sure to check and test SRT settings on your sender side. The default values + do not take into account your specific scenarios and do not work well. If + necessary, ask us and we will help you. + + Please note that 1 connection and 1 protocol can be used at a single moment in + time per unique stream key input. Trying to send 2+ connection requests into the + single `push_url_srt`, or 2+ protocols at once will not lead to a result. + + For example, transcoding process will fail if: + + - you are pushing primary and backup SRT to the same single `push_url_srt` + simultaneously + - you are pushing RTMP to `push_url` and SRT to `push_url_srt` simultaneously + + See more information and best practices about SRT protocol in the Product + Documentation. + """ + + push_url_whip: Optional[str] = None + """URL to PUSH WebRTC stream to our server using WHIP protocol. + + **WebRTC WHIP to LL-HLS and DASH** + + Video Streaming supports WebRTC HTTP Ingest Protocol (WHIP), and WebRTC to + HLS/DASH converter. As a result you can stream from web broswers natively. + + **WebRTC WHIP server** + + We have dedicated WebRTC WHIP servers in our infrastructure. WebRTC WHIP server + organizes both signaling and receives video data. Signaling is a term to + describe communication between WebRTC endpoints, needed to initiate and maintain + a session. WHIP is an open specification for a simple signaling protocol for + starting WebRTC sessions in an outgoing direction, (i.e., streaming from your + device). + + There is the primary link only for WHIP, so no backup link. + + **WebRTC stream encoding parameters** + + At least one video and audio track both must be present in the stream: + + - Video must be encoded with H.264. + - Audio must be encoded with OPUS. + + Note. Specifically for WebRTC mode a method of constant transcoding with an + initial given resolution is used. This means that if WebRTC in the end-user's + browser decides to reduce the quality or resolution of the master stream (to let + say 360p) due to restrictions on the end-user's device (network conditions, CPU + consumption, etc.), the transcoder will still continue to transcode the reduced + stream to the initial resolution (let say 1080p ABR). When the restrictions on + the end-user's device are removed, quiality will improve again. + + **WebRTC WHIP Client** + + We provide a convenient WebRTC WHIP library for working in browsers. You can use + our library, or any other you prefer. Simple example of usage is here: + https://stackblitz.com/edit/stackblitz-starters-j2r9ar?file=index.html + + Also try to use the feature in UI of the Customer Portal. In the Streaming + section inside the settings of a specific live stream, a new section "Quick + start in browser" has been added. + + Please note that 1 connection and 1 protocol can be used at a single moment in + time per unique stream key input. Trying to send 2+ connection requests into the + single `push_url_whip`, or 2+ protocols at once will not lead to a result. + + For example, transcoding process will fail if: + + - you are pushing primary and backup WHIP to the same single `push_url_whip` + simultaneously + - you are pushing WHIP to `push_url_whip` and RTMP to `push_url` simultaneously + + More information in the Product Documentation on the website. + """ + + quality_set_id: Optional[int] = None + """ + Custom quality set ID for transcoding, if transcoding is required according to + your conditions. Look at GET /`quality_sets` method + """ + + record_type: Optional[Literal["origin", "transcoded"]] = None + """Method of recording a stream. + + Specifies the source from which the stream will be recorded: original or + transcoded. + + Types: + + - "origin" – To record RMTP/SRT/etc original clean media source. + - "transcoded" – To record the output transcoded version of the stream, + including overlays, texts, logos, etc. additional media layers. + """ + + recording_duration: Optional[float] = None + """Duration of current recording in seconds if recording is enabled for the stream""" + + screenshot: Optional[str] = None + """ + An instant screenshot taken from a live stream, and available as a static JPEG + image. Resolution 1080 pixels wide, or less if the original stream has a lower + resolution. + + Screenshot is taken every 10 seconds while the stream is live. This field + contains a link to the last screenshot created by the system. Screenshot history + is not stored, so if you need a series of screenshots over time, then download + them. + """ + + started_at_backup: Optional[str] = None + """Time of the last session when backup server started receiving the stream. + + Datetime in ISO 8601 + """ + + started_at_primary: Optional[str] = None + """Time of the last session when main server started receiving the stream. + + Datetime in ISO 8601. + + This means that if the stream was started 1 time, then here will be the time it + was started. If the stream was started several times, or restarted on your side, + then only the time of the last session is displayed here. + """ + + stream_source_type: Optional[Literal["rtmp", "srt", "webrtc", "https"]] = None + """ + For the current transcoding, this specifies the source protocol: RTMP, SRT, + WebRTC, or HTTPS. This does not specify which source is used primary or backup, + only the source protocol type. If transcoding is inactive, the value will be + null. + """ + + transcoded_qualities: Optional[List[str]] = None + """Array of qualities to which live stream is transcoded""" + + transcoding_speed: Optional[float] = None + """Speed of transcoding the stream. + + Mainly it must be 1.0 for real-time processing. May be less than 1.0 if your + stream has problems in delivery due to your local internet provider's + conditions, or the stream does not meet stream inbound requirements. See + Knowledge Base for details. + """ + + uri: Optional[str] = None + """When using PULL method, this is the URL to pull a stream from. + + You can specify multiple addresses separated by a space (" "), so you can + organize a backup plan. In this case, the specified addresses will be selected + one by one using round robin scheduling. If the first address does not respond, + then the next one in the list will be automatically requested, returning to the + first and so on in a circle. Also, if the sucessfully working stream stops + sending data, then the next one will be selected according to the same scheme. + + After 2 hours of inactivity of your original stream, the system stops PULL + requests and the stream is deactivated (the "active" field switches to "false"). + + Please, note that this field is for PULL only, so is not suitable for PUSH. Look + at fields "push_url" and "push_url_srt" from GET method. + """ + + video_height: Optional[float] = None + """Current height of frame of the original stream, if stream is transcoding""" + + video_width: Optional[float] = None + """Current width of frame of the original stream, if stream is transcoding""" diff --git a/src/gcore/types/streaming/stream_create_clip_params.py b/src/gcore/types/streaming/stream_create_clip_params.py new file mode 100644 index 00000000..2a2f365a --- /dev/null +++ b/src/gcore/types/streaming/stream_create_clip_params.py @@ -0,0 +1,60 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["StreamCreateClipParams"] + + +class StreamCreateClipParams(TypedDict, total=False): + duration: Required[int] + """Requested segment duration in seconds to be cut. + + Please, note that cutting is based on the idea of instantly creating a clip, + instead of precise timing. So final segment may be: + + - Less than the specified value if there is less data in the DVR than the + requested segment. + - Greater than the specified value, because segment is aligned to the first and + last key frames of already stored fragment in DVR, this way -1 and +1 chunks + can be added to left and right. + + Duration of cutted segment cannot be greater than DVR duration for this stream. + Therefore, to change the maximum, use "dvr_duration" parameter of this stream. + """ + + expiration: int + """Expire time of the clip via a public link. + + Unix timestamp in seconds, absolute value. + + This is the time how long the instant clip will be stored in the server memory + and can be accessed via public HLS/MP4 links. Download and/or use the instant + clip before this time expires. + + After the time has expired, the clip is deleted from memory and is no longer + available via the link. You need to create a new segment, or use + `vod_required: true` attribute. + + If value is omitted, then expiration is counted as +3600 seconds (1 hour) to the + end of the clip (i.e. `unix timestamp = + + 3600`). + + Allowed range: 1m <= expiration <= 4h. + + Example: + `24.05.2024 14:00:00 (GMT) + 60 seconds of duration + 3600 seconds of expiration = 24.05.2024 15:01:00 (GMT) is Unix timestamp = 1716562860` + """ + + start: int + """Starting point of the segment to cut. + + Unix timestamp in seconds, absolute value. Example: + `24.05.2024 14:00:00 (GMT) is Unix timestamp = 1716559200` + + If a value from the past is specified, it is used as the starting point for the + segment to cut. If the value is omitted, then clip will start from now. + """ + + vod_required: bool + """Indicates if video needs to be stored also as permanent VOD""" diff --git a/src/gcore/types/streaming/stream_create_params.py b/src/gcore/types/streaming/stream_create_params.py new file mode 100644 index 00000000..565c9dcb --- /dev/null +++ b/src/gcore/types/streaming/stream_create_params.py @@ -0,0 +1,168 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["StreamCreateParams"] + + +class StreamCreateParams(TypedDict, total=False): + name: Required[str] + """Stream name. + + Often used as a human-readable name for the stream, but can contain any text you + wish. The values are not unique and may be repeated. + + Examples: + + - Conference in July + - Stream #10003 + - Open-Air Camera #31 Backstage + - 480fd499-2de2-4988-bc1a-a4eebe9818ee + """ + + active: bool + """Stream switch between on and off. + + This is not an indicator of the status "stream is receiving and it is LIVE", but + rather an on/off switch. + + When stream is switched off, there is no way to process it: PULL is deactivated + and PUSH will return an error. + + - true – stream can be processed + - false – stream is off, and cannot be processed + """ + + auto_record: bool + """Enables autotomatic recording of the stream when it started. + + So you don't need to call recording manually. + + Result of recording is automatically added to video hosting. For details see the + /streams/`start_recording` method and in knowledge base + + Values: + + - true – auto recording is enabled + - false – auto recording is disabled + """ + + broadcast_ids: Iterable[int] + """IDs of broadcasts which will include this stream""" + + cdn_id: int + """ + ID of custom CDN resource from which the content will be delivered (only if you + know what you do) + """ + + client_entity_data: str + """ + Custom meta field designed to store your own extra information about a video + entity: video source, video id, parameters, etc. We do not use this field in any + way when processing the stream. You can store any data in any format (string, + json, etc), saved as a text string. Example: + `client_entity_data = '{ "seq_id": "1234567890", "name": "John Doe", "iat": 1516239022 }'` + """ + + client_user_id: int + """Custom meta field for storing the Identifier in your system. + + We do not use this field in any way when processing the stream. Example: + `client_user_id = 1001` + """ + + dvr_duration: int + """DVR duration in seconds if DVR feature is enabled for the stream. + + So this is duration of how far the user can rewind the live stream. + + `dvr_duration` range is [30...14400]. + + Maximum value is 4 hours = 14400 seconds. If you need more, ask the Support Team + please. + """ + + dvr_enabled: bool + """Enables DVR for the stream: + + - true – DVR is enabled + - false – DVR is disabled + """ + + hls_mpegts_endlist_tag: bool + """ + Add `#EXT-X-ENDLIST` tag within .m3u8 playlist after the last segment of a live + stream when broadcast is ended. + """ + + html_overlay: bool + """ + Switch on mode to insert and display real-time HTML overlay widgets on top of + live streams + """ + + projection: Literal["regular", "vr360", "vr180", "vr360tb"] + """ + Visualization mode for 360° streams, how the stream is rendered in our web + player ONLY. If you would like to show video 360° in an external video player, + then use parameters of that video player. + + Modes: + + - regular – regular “flat” stream + - vr360 – display stream in 360° mode + - vr180 – display stream in 180° mode + - vr360tb – display stream in 3D 360° mode Top-Bottom + """ + + pull: bool + """Indicates if stream is pulled from external server or not. + + Has two possible values: + + - true – stream is received by PULL method. Use this when need to get stream + from external server. + - false – stream is received by PUSH method. Use this when need to send stream + from end-device to our Streaming Platform, i.e. from your encoder, mobile app + or OBS Studio. + """ + + quality_set_id: int + """ + Custom quality set ID for transcoding, if transcoding is required according to + your conditions. Look at GET /`quality_sets` method + """ + + record_type: Literal["origin", "transcoded"] + """Method of recording a stream. + + Specifies the source from which the stream will be recorded: original or + transcoded. + + Types: + + - "origin" – To record RMTP/SRT/etc original clean media source. + - "transcoded" – To record the output transcoded version of the stream, + including overlays, texts, logos, etc. additional media layers. + """ + + uri: str + """When using PULL method, this is the URL to pull a stream from. + + You can specify multiple addresses separated by a space (" "), so you can + organize a backup plan. In this case, the specified addresses will be selected + one by one using round robin scheduling. If the first address does not respond, + then the next one in the list will be automatically requested, returning to the + first and so on in a circle. Also, if the sucessfully working stream stops + sending data, then the next one will be selected according to the same scheme. + + After 2 hours of inactivity of your original stream, the system stops PULL + requests and the stream is deactivated (the "active" field switches to "false"). + + Please, note that this field is for PULL only, so is not suitable for PUSH. Look + at fields "push_url" and "push_url_srt" from GET method. + """ diff --git a/src/gcore/types/streaming/stream_list_clips_response.py b/src/gcore/types/streaming/stream_list_clips_response.py new file mode 100644 index 00000000..851546a7 --- /dev/null +++ b/src/gcore/types/streaming/stream_list_clips_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .clip import Clip + +__all__ = ["StreamListClipsResponse"] + +StreamListClipsResponse: TypeAlias = List[Clip] diff --git a/src/gcore/types/streaming/stream_list_params.py b/src/gcore/types/streaming/stream_list_params.py new file mode 100644 index 00000000..b0aa4a67 --- /dev/null +++ b/src/gcore/types/streaming/stream_list_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["StreamListParams"] + + +class StreamListParams(TypedDict, total=False): + page: int + """Query parameter. Use it to list the paginated content""" + + with_broadcasts: int + """Query parameter. + + Set to 1 to get details of the broadcasts associated with the stream + """ diff --git a/src/gcore/types/streaming/stream_series.py b/src/gcore/types/streaming/stream_series.py new file mode 100644 index 00000000..4e14f573 --- /dev/null +++ b/src/gcore/types/streaming/stream_series.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["StreamSeries", "StreamSeriesItem", "StreamSeriesItemMetrics"] + + +class StreamSeriesItemMetrics(BaseModel): + streams: List[int] + + +class StreamSeriesItem(BaseModel): + client: int + + metrics: StreamSeriesItemMetrics + + +StreamSeries: TypeAlias = List[StreamSeriesItem] diff --git a/src/gcore/types/streaming/stream_start_recording_response.py b/src/gcore/types/streaming/stream_start_recording_response.py new file mode 100644 index 00000000..ba3326b6 --- /dev/null +++ b/src/gcore/types/streaming/stream_start_recording_response.py @@ -0,0 +1,82 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = [ + "StreamStartRecordingResponse", + "Data", + "DataStream", + "DataStreamClient", + "Warning", + "WarningMeta", + "WarningSourceObject", +] + + +class DataStreamClient(BaseModel): + id: Optional[int] = None + """Client ID""" + + storage_limit_mb: Optional[int] = None + """Current storage limit for client by megabytes""" + + storage_usage_mb: Optional[float] = None + """Current storage usage for client by megabytes""" + + +class DataStream(BaseModel): + id: Optional[int] = None + """Stream ID""" + + client: Optional[DataStreamClient] = None + + +class Data(BaseModel): + """Stream data""" + + stream: Optional[DataStream] = None + + +class WarningMeta(BaseModel): + """storage usage state for client""" + + storage_limit_mb: Optional[int] = None + """Current storage limit for client by megabytes""" + + storage_usage_mb: Optional[float] = None + """Current storage usage for client by megabytes""" + + +class WarningSourceObject(BaseModel): + """Warning source object""" + + id: Optional[int] = None + """Client ID""" + + type: Optional[Literal["client"]] = None + """Object type (class)""" + + +class Warning(BaseModel): + key: Optional[Literal["client_storage_almost_exceeded"]] = None + """current warning key""" + + meta: Optional[WarningMeta] = None + """storage usage state for client""" + + source_object: Optional[WarningSourceObject] = None + """Warning source object""" + + +class StreamStartRecordingResponse(BaseModel): + data: Optional[Data] = None + """Stream data""" + + errors: Optional[List[object]] = None + """List of errors received on attempt to start recording process""" + + warnings: Optional[List[Warning]] = None + """List of warnings received on starting recording process""" diff --git a/src/gcore/types/streaming/stream_update_params.py b/src/gcore/types/streaming/stream_update_params.py new file mode 100644 index 00000000..f880f872 --- /dev/null +++ b/src/gcore/types/streaming/stream_update_params.py @@ -0,0 +1,172 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["StreamUpdateParams", "Stream"] + + +class StreamUpdateParams(TypedDict, total=False): + stream: Stream + + +class Stream(TypedDict, total=False): + name: Required[str] + """Stream name. + + Often used as a human-readable name for the stream, but can contain any text you + wish. The values are not unique and may be repeated. + + Examples: + + - Conference in July + - Stream #10003 + - Open-Air Camera #31 Backstage + - 480fd499-2de2-4988-bc1a-a4eebe9818ee + """ + + active: bool + """Stream switch between on and off. + + This is not an indicator of the status "stream is receiving and it is LIVE", but + rather an on/off switch. + + When stream is switched off, there is no way to process it: PULL is deactivated + and PUSH will return an error. + + - true – stream can be processed + - false – stream is off, and cannot be processed + """ + + auto_record: bool + """Enables autotomatic recording of the stream when it started. + + So you don't need to call recording manually. + + Result of recording is automatically added to video hosting. For details see the + /streams/`start_recording` method and in knowledge base + + Values: + + - true – auto recording is enabled + - false – auto recording is disabled + """ + + broadcast_ids: Iterable[int] + """IDs of broadcasts which will include this stream""" + + cdn_id: int + """ + ID of custom CDN resource from which the content will be delivered (only if you + know what you do) + """ + + client_entity_data: str + """ + Custom meta field designed to store your own extra information about a video + entity: video source, video id, parameters, etc. We do not use this field in any + way when processing the stream. You can store any data in any format (string, + json, etc), saved as a text string. Example: + `client_entity_data = '{ "seq_id": "1234567890", "name": "John Doe", "iat": 1516239022 }'` + """ + + client_user_id: int + """Custom meta field for storing the Identifier in your system. + + We do not use this field in any way when processing the stream. Example: + `client_user_id = 1001` + """ + + dvr_duration: int + """DVR duration in seconds if DVR feature is enabled for the stream. + + So this is duration of how far the user can rewind the live stream. + + `dvr_duration` range is [30...14400]. + + Maximum value is 4 hours = 14400 seconds. If you need more, ask the Support Team + please. + """ + + dvr_enabled: bool + """Enables DVR for the stream: + + - true – DVR is enabled + - false – DVR is disabled + """ + + hls_mpegts_endlist_tag: bool + """ + Add `#EXT-X-ENDLIST` tag within .m3u8 playlist after the last segment of a live + stream when broadcast is ended. + """ + + html_overlay: bool + """ + Switch on mode to insert and display real-time HTML overlay widgets on top of + live streams + """ + + projection: Literal["regular", "vr360", "vr180", "vr360tb"] + """ + Visualization mode for 360° streams, how the stream is rendered in our web + player ONLY. If you would like to show video 360° in an external video player, + then use parameters of that video player. + + Modes: + + - regular – regular “flat” stream + - vr360 – display stream in 360° mode + - vr180 – display stream in 180° mode + - vr360tb – display stream in 3D 360° mode Top-Bottom + """ + + pull: bool + """Indicates if stream is pulled from external server or not. + + Has two possible values: + + - true – stream is received by PULL method. Use this when need to get stream + from external server. + - false – stream is received by PUSH method. Use this when need to send stream + from end-device to our Streaming Platform, i.e. from your encoder, mobile app + or OBS Studio. + """ + + quality_set_id: int + """ + Custom quality set ID for transcoding, if transcoding is required according to + your conditions. Look at GET /`quality_sets` method + """ + + record_type: Literal["origin", "transcoded"] + """Method of recording a stream. + + Specifies the source from which the stream will be recorded: original or + transcoded. + + Types: + + - "origin" – To record RMTP/SRT/etc original clean media source. + - "transcoded" – To record the output transcoded version of the stream, + including overlays, texts, logos, etc. additional media layers. + """ + + uri: str + """When using PULL method, this is the URL to pull a stream from. + + You can specify multiple addresses separated by a space (" "), so you can + organize a backup plan. In this case, the specified addresses will be selected + one by one using round robin scheduling. If the first address does not respond, + then the next one in the list will be automatically requested, returning to the + first and so on in a circle. Also, if the sucessfully working stream stops + sending data, then the next one will be selected according to the same scheme. + + After 2 hours of inactivity of your original stream, the system stops PULL + requests and the stream is deactivated (the "active" field switches to "false"). + + Please, note that this field is for PULL only, so is not suitable for PUSH. Look + at fields "push_url" and "push_url_srt" from GET method. + """ diff --git a/src/gcore/types/streaming/streams/__init__.py b/src/gcore/types/streaming/streams/__init__.py new file mode 100644 index 00000000..e5f7a9b0 --- /dev/null +++ b/src/gcore/types/streaming/streams/__init__.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .overlay import Overlay as Overlay +from .overlay_create_params import OverlayCreateParams as OverlayCreateParams +from .overlay_list_response import OverlayListResponse as OverlayListResponse +from .overlay_update_params import OverlayUpdateParams as OverlayUpdateParams +from .overlay_create_response import OverlayCreateResponse as OverlayCreateResponse +from .overlay_update_multiple_params import OverlayUpdateMultipleParams as OverlayUpdateMultipleParams +from .overlay_update_multiple_response import OverlayUpdateMultipleResponse as OverlayUpdateMultipleResponse diff --git a/src/gcore/types/streaming/streams/overlay.py b/src/gcore/types/streaming/streams/overlay.py new file mode 100644 index 00000000..37f36798 --- /dev/null +++ b/src/gcore/types/streaming/streams/overlay.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["Overlay"] + + +class Overlay(BaseModel): + id: int + """ID of the overlay""" + + created_at: str + """Datetime of creation in ISO 8601""" + + stream_id: int + """ID of a stream to which it is attached""" + + updated_at: str + """Datetime of last update in ISO 8601""" + + url: str + """Valid http/https URL to an HTML page/widget""" + + height: Optional[int] = None + """Height of the widget""" + + stretch: Optional[bool] = None + """Switch of auto scaling the widget. + + Must not be used as "true" simultaneously with the coordinate installation + method (w, h, x, y). + """ + + width: Optional[int] = None + """Width of the widget""" + + x: Optional[int] = None + """Coordinate of left upper corner""" + + y: Optional[int] = None + """Coordinate of left upper corner""" diff --git a/src/gcore/types/streaming/streams/overlay_create_params.py b/src/gcore/types/streaming/streams/overlay_create_params.py new file mode 100644 index 00000000..55614169 --- /dev/null +++ b/src/gcore/types/streaming/streams/overlay_create_params.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["OverlayCreateParams", "Body"] + + +class OverlayCreateParams(TypedDict, total=False): + body: Iterable[Body] + + +class Body(TypedDict, total=False): + url: Required[str] + """Valid http/https URL to an HTML page/widget""" + + height: int + """Height of the widget""" + + stretch: bool + """Switch of auto scaling the widget. + + Must not be used as "true" simultaneously with the coordinate installation + method (w, h, x, y). + """ + + width: int + """Width of the widget""" + + x: int + """Coordinate of left upper corner""" + + y: int + """Coordinate of left upper corner""" diff --git a/src/gcore/types/streaming/streams/overlay_create_response.py b/src/gcore/types/streaming/streams/overlay_create_response.py new file mode 100644 index 00000000..02ccd9f1 --- /dev/null +++ b/src/gcore/types/streaming/streams/overlay_create_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .overlay import Overlay + +__all__ = ["OverlayCreateResponse"] + +OverlayCreateResponse: TypeAlias = List[Overlay] diff --git a/src/gcore/types/streaming/streams/overlay_list_response.py b/src/gcore/types/streaming/streams/overlay_list_response.py new file mode 100644 index 00000000..e6dffcfb --- /dev/null +++ b/src/gcore/types/streaming/streams/overlay_list_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .overlay import Overlay + +__all__ = ["OverlayListResponse"] + +OverlayListResponse: TypeAlias = List[Overlay] diff --git a/src/gcore/types/streaming/streams/overlay_update_multiple_params.py b/src/gcore/types/streaming/streams/overlay_update_multiple_params.py new file mode 100644 index 00000000..c14fa0fc --- /dev/null +++ b/src/gcore/types/streaming/streams/overlay_update_multiple_params.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["OverlayUpdateMultipleParams", "Body"] + + +class OverlayUpdateMultipleParams(TypedDict, total=False): + body: Iterable[Body] + + +class Body(TypedDict, total=False): + id: Required[int] + """ID of the overlay""" + + height: int + """Height of the widget""" + + stretch: bool + """Switch of auto scaling the widget. + + Must not be used as "true" simultaneously with the coordinate installation + method (w, h, x, y). + """ + + url: str + """Valid http/https URL to an HTML page/widget""" + + width: int + """Width of the widget""" + + x: int + """Coordinate of left upper corner""" + + y: int + """Coordinate of left upper corner""" diff --git a/src/gcore/types/streaming/streams/overlay_update_multiple_response.py b/src/gcore/types/streaming/streams/overlay_update_multiple_response.py new file mode 100644 index 00000000..f5c1b68b --- /dev/null +++ b/src/gcore/types/streaming/streams/overlay_update_multiple_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .overlay import Overlay + +__all__ = ["OverlayUpdateMultipleResponse"] + +OverlayUpdateMultipleResponse: TypeAlias = List[Overlay] diff --git a/src/gcore/types/streaming/streams/overlay_update_params.py b/src/gcore/types/streaming/streams/overlay_update_params.py new file mode 100644 index 00000000..524be0ba --- /dev/null +++ b/src/gcore/types/streaming/streams/overlay_update_params.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["OverlayUpdateParams"] + + +class OverlayUpdateParams(TypedDict, total=False): + stream_id: Required[int] + + height: int + """Height of the widget""" + + stretch: bool + """Switch of auto scaling the widget. + + Must not be used as "true" simultaneously with the coordinate installation + method (w, h, x, y). + """ + + url: str + """Valid http/https URL to an HTML page/widget""" + + width: int + """Width of the widget""" + + x: int + """Coordinate of left upper corner""" + + y: int + """Coordinate of left upper corner""" diff --git a/src/gcore/types/streaming/subtitle.py b/src/gcore/types/streaming/subtitle.py new file mode 100644 index 00000000..6d02a260 --- /dev/null +++ b/src/gcore/types/streaming/subtitle.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .subtitle_base import SubtitleBase + +__all__ = ["Subtitle"] + + +class Subtitle(SubtitleBase): + id: Optional[int] = None + """ID of subtitle file""" diff --git a/src/gcore/types/streaming/subtitle_base.py b/src/gcore/types/streaming/subtitle_base.py new file mode 100644 index 00000000..4feac312 --- /dev/null +++ b/src/gcore/types/streaming/subtitle_base.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["SubtitleBase"] + + +class SubtitleBase(BaseModel): + language: Optional[str] = None + """3-letter language code according to ISO-639-2 (bibliographic code)""" + + name: Optional[str] = None + """Name of subtitle file""" + + vtt: Optional[str] = None + """Full text of subtitles/captions, with escaped "\n" ("\r") symbol of new line""" diff --git a/src/gcore/types/streaming/subtitle_base_param.py b/src/gcore/types/streaming/subtitle_base_param.py new file mode 100644 index 00000000..e50022f2 --- /dev/null +++ b/src/gcore/types/streaming/subtitle_base_param.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["SubtitleBaseParam"] + + +class SubtitleBaseParam(TypedDict, total=False): + language: str + """3-letter language code according to ISO-639-2 (bibliographic code)""" + + name: str + """Name of subtitle file""" + + vtt: str + """Full text of subtitles/captions, with escaped "\n" ("\r") symbol of new line""" diff --git a/src/gcore/types/streaming/unique_viewers.py b/src/gcore/types/streaming/unique_viewers.py new file mode 100644 index 00000000..0d8549c0 --- /dev/null +++ b/src/gcore/types/streaming/unique_viewers.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["UniqueViewers", "Data"] + + +class Data(BaseModel): + date: str + + unique_ips: int + + id: Optional[int] = None + + browser: Optional[str] = None + + country: Optional[str] = None + + event: Optional[str] = None + + host: Optional[str] = None + + ip: Optional[str] = None + + os: Optional[str] = None + + platform: Optional[str] = None + + type: Optional[str] = None + + +class UniqueViewers(BaseModel): + data: Optional[List[Data]] = None diff --git a/src/gcore/types/streaming/unique_viewers_cdn.py b/src/gcore/types/streaming/unique_viewers_cdn.py new file mode 100644 index 00000000..ab3f1f1e --- /dev/null +++ b/src/gcore/types/streaming/unique_viewers_cdn.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["UniqueViewersCDN", "Data"] + + +class Data(BaseModel): + type: str + + uniqs: int + + +class UniqueViewersCDN(BaseModel): + data: Optional[List[Data]] = None diff --git a/src/gcore/types/streaming/video.py b/src/gcore/types/streaming/video.py new file mode 100644 index 00000000..f6a405ee --- /dev/null +++ b/src/gcore/types/streaming/video.py @@ -0,0 +1,520 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["Video", "ConvertedVideo"] + + +class ConvertedVideo(BaseModel): + id: Optional[int] = None + """ID of the converted file of the specific quality""" + + error: Optional[str] = None + """Video processing error text in this quality""" + + height: Optional[int] = None + """Height in pixels of the converted video file of the specific quality. + + Can be `null` for audio-only files. + """ + + mp4_url: Optional[str] = None + """ + A URL to a rendition file of the specified quality in MP4 format for + downloading. + + **Download methods** + + For each converted video, additional download endpoints are available under + `converted_videos`/`mp4_urls`. An MP4 download enpoints: + + 1. `/videos/{client_id}_{slug}/{filename}.mp4` + 2. `/videos/{client_id}_{slug}/{filename}.mp4/download` + 3. `/videos/{client_id}_{slug}/{filename}.mp4/download={custom_filename}` + + The first option returns the file as is. Response will be: + + ``` + GET .mp4 + ... + content-type: video/mp4 + ``` + + The second option with `/download` will respond with HTTP response header that + directly tells browsers to download the file instead of playing it in the + browser: + + ``` + GET .mp4/download + ... + content-type: video/mp4 + content-disposition: attachment + access-control-expose-headers: Content-Disposition + ``` + + The third option allows you to set a custom name for the file being downloaded. + You can optionally specify a custom filename (just name excluding the .mp4 + extension) using the download= query. + + Filename constraints: + + - Length: 1-255 characters + - Must NOT include the .mp4 extension (it is added automatically) + - Allowed characters: a-z, A-Z, 0-9, \\__(underscore), -(dash), .(dot) + - First character cannot be .(dot) + - Example valid filenames: `holiday2025`, `_backup.final`, `clip-v1.2` + + ``` + GET .mp4/download={custom_filename} + ... + content-type: video/mp4 + content-disposition: attachment; filename="{custom_filename}.mp4" + access-control-expose-headers: Content-Disposition + ``` + + Examples: + + - MP4: + `https://demo-public.gvideo.io/videos/2675_1OFgHZ1FWZNNvx1A/qid3567v1_h264_4050_1080.mp4/download` + - MP4 with custom download filename: + `https://demo-public.gvideo.io/videos/2675_1OFgHZ1FWZNNvx1A/qid3567v1_h264_4050_1080.mp4/download=highlights_v1.1_2025-05-30` + + **Default MP4 file name structure** + + Link to the file {filename} contains information about the encoding method using + format: + + `___.mp4` + + - `` – Internal quality identifier and file version. Please do + not use it, can be changed at any time without any notice. + - `` – Codec name that was used to encode the video, or audio codec if it + is an audio-only file. + - `` – Encoding bitrate in Kbps. + - `` – Video height, or word "audio" if it is an audio-only file. + + Note that this link format has been applied since 14.08.2024. If the video + entity was uploaded earlier, links may have old simplified format. + + Example: `/videos/{client_id}_{slug}/qid3567v1_h264_4050_1080.mp4` + + **Dynamic speed limiting** This mode sets different limits for different users + or for different types of content. The speed is adjusted based on requests with + the “speed” and “buffer” arguments. + + Example: `?speed=50k&buffer=500k` + + Read more in Product Documentation in CDN section "Network limits". + + **Secure token authentication for MP4 (updated)** + + Access to MP4 download links only can be protected using advanced secure tokens + passed as query parameters. + + Token generation uses the entire MP4 path, which ensures the token only grants + access to a specific quality/version of the video. This prevents unintended + access to other bitrate versions of an ABR stream. + + Token Query Parameters: + + - token: The generated hash + - expires: Expiration timestamp + - speed: (optional) Speed limit in bytes/sec, or empty string + - buffer: (optional) Buffer size in bytes, or empty string + + Optional (for IP-bound tokens): + + - ip: The user’s IP address Example: + `?md5=QX39c77lbQKvYgMMAvpyMQ&expires=1743167062` + + Read more in Product Documentation in Streaming section "Protected temporarily + link". + """ + + name: Optional[str] = None + """Specific quality name""" + + progress: Optional[int] = None + """Status of transcoding into the specific quality, from 0 to 100""" + + size: Optional[int] = None + """Size in bytes of the converted file of the specific quality. + + Can be `null` until transcoding is fully completed. + """ + + status: Optional[Literal["processing", "complete", "error"]] = None + """Status of transcoding: + + - processing – video is being transcoded to this quality, + - complete – quality is fully processed, + - error – quality processing error, see parameter "error". + """ + + width: Optional[int] = None + """Width in pixels of the converted video file of the specified quality. + + Can be `null` for audio files. + """ + + +class Video(BaseModel): + id: Optional[int] = None + """Video ID""" + + ad_id: Optional[int] = None + """ID of ad that should be shown. + + If empty the default ad is show. If there is no default ad, no ad is shownю + """ + + cdn_views: Optional[int] = None + """Total number of video views. + + It is calculated based on the analysis of all views, no matter in which player. + """ + + client_id: Optional[int] = None + """Client ID""" + + client_user_id: Optional[int] = None + """Custom meta field for storing the Identifier in your system. + + We do not use this field in any way when processing the stream. Example: + `client_user_id = 1001` + """ + + converted_videos: Optional[List[ConvertedVideo]] = None + """Array of data about each transcoded quality""" + + custom_iframe_url: Optional[str] = None + """Custom URL of Iframe for video player to be used in share panel in player. + + Auto generated Iframe URL provided by default. + """ + + dash_url: Optional[str] = None + """ + A URL to a master playlist MPEG-DASH (master.mpd) with CMAF or WebM based + chunks. + + Chunk type will be selected automatically for each quality: + + - CMAF for H264 and H265 codecs. + - WebM for AV1 codec. + + This URL is a link to the main manifest. But you can also manually specify + suffix-options that will allow you to change the manifest to your request: + + ``` + /videos/{client_id}_{slug}/master[-min-N][-max-N][-(h264|hevc|av1)].mpd + ``` + + List of suffix-options: + + - [-min-N] – ABR soft limitation of qualities from below. + - [-max-N] – ABR soft limitation of qualities from above. + - [-(h264|hevc|av1) – Video codec soft limitation. Applicable if the video was + transcoded into multiple codecs H264, H265 and AV1 at once, but you want to + return just 1 video codec in a manifest. Read the Product Documentation for + details. + + Read more what is ABR soft-limiting in the "hls_url" field above. + + Caution. Solely master.mpd is officially documented and intended for your use. + Any additional internal manifests, sub-manifests, parameters, chunk names, file + extensions, and related components are internal infrastructure entities. These + may undergo modifications without prior notice, in any manner or form. It is + strongly advised not to store them in your database or cache them on your end. + """ + + description: Optional[str] = None + """Additional text field for video description""" + + duration: Optional[int] = None + """Video duration in milliseconds. + + May differ from "origin_video_duration" value if the video was uploaded with + clipping through the parameters "clip_start_seconds" and "clip_duration_seconds" + """ + + error: Optional[str] = None + """Video processing error text will be saved here if "status: error" """ + + hls_cmaf_url: Optional[str] = None + """A URL to a master playlist HLS (master-cmaf.m3u8) with CMAF-based chunks. + + Chunks are in fMP4 container. It's a code-agnostic container, which allows to + use any like H264, H265, AV1, etc. + + It is possible to use the same suffix-options as described in the "hls_url" + attribute. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + """ + + hls_url: Optional[str] = None + """ + A URL to a master playlist HLS (master.m3u8). Chunk type will be selected + automatically: + + - TS if your video was encoded to H264 only. + - CMAF if your video was encoded additionally to H265 and/or AV1 codecs (as + Apple does not support these codecs over MPEG TS, and they are not + standardized in TS-container). + + You can also manually specify suffix-options that will allow you to change the + manifest to your request: + + ``` + /videos/{client_id}_{video_slug}/master[-cmaf][-min-N][-max-N][-img][-(h264|hevc|av1)].m3u8 + ``` + + List of suffix-options: + + - [-cmaf] – getting HLS CMAF version of the manifest. Look at the `hls_cmaf_url` + field. + - [-min-N] – ABR soft limitation of qualities from below. + - [-max-N] – ABR soft limitation of qualities from above. + - [-img] – Roku trick play: to add tiles directly into .m3u8 manifest. Read the + Product Documentation for details. + - [-(h264|hevc|av1) – Video codec soft limitation. Applicable if the video was + transcoded into multiple codecs H264, H265 and AV1 at once, but you want to + return just 1 video codec in a manifest. Read the Product Documentation for + details. + + ABR soft-limiting: Soft limitation of the list of qualities allows you to return + not the entire list of transcoded qualities for a video, but only those you + need. For example, the video is available in 7 qualities from 360p to 4K, but + you want to return not more than 480p only due to the conditions of distribution + of content to a specific end-user (i.e. free account): ABR soft-limiting + examples: + + - To a generic `.../master.m3u8` manifest + - Add a suffix-option to limit quality `.../master-max-480.m3u8` + - Add a suffix-option to limit quality and codec + `.../master-min-320-max-320-h264.m3u8` For more details look at the Product + Documentation. + + Caution. Solely master.m3u8 (and master[-options].m3u8) is officially documented + and intended for your use. Any additional internal manifests, sub-manifests, + parameters, chunk names, file extensions, and related components are internal + infrastructure entities. These may undergo modifications without prior notice, + in any manner or form. It is strongly advised not to store them in your database + or cache them on your end. + """ + + iframe_url: Optional[str] = None + """A URL to a built-in HTML video player with the video inside. + + It can be inserted into an iframe on your website and the video will + automatically play in all browsers. + + The player can be opened or shared via this direct link. Also the video player + can be integrated into your web pages using the Iframe tag. + + Example of usage on a web page: + + + + + There are some link modificators you can specify and add manually: + + - ?`no_low_latency` – player is forced to use non-low-latency streams HLS + MPEG-TS, instead of MPEG-DASH CMAF or HLS/LL-HLS CMAF. + - ?t=(integer) – time to start playback from specified point in the video. + Applicable for VOD only. + - ?`sub_lang`=(language) – force subtitles to specific language (2 letters ISO + 639 code of a language). + - Read more in the Product Documentation. + """ + + name: Optional[str] = None + """Title of the video. + + Often used as a human-readable name of the video, but can contain any text you + wish. The values are not unique and may be repeated. Examples: + + - Educational training 2024-03-29 + - Series X S3E14, The empire strikes back + - 480fd499-2de2-4988-bc1a-a4eebe9818ee + """ + + origin_size: Optional[int] = None + """Size of original file""" + + origin_url: Optional[str] = None + """URL to an original file from which the information for transcoding was taken. + + May contain a link for scenarios: + + - If the video was downloaded from another origin + - If the video is a recording of a live stream + - Otherwise it is "null" + + **Copy from another server** URL to an original file that was downloaded. Look + at method "Copy from another server" in POST /videos. **Recording of an original + live stream** + + URL to the original non-transcoded stream recording with original quality, saved + in MP4 format. File is created immediately after the completion of the stream + recording. The stream from which the recording was made is reflected in + "stream_id" field. + + Can be used for internal operations when a recording needs to be received faster + than the transcoded versions are ready. But this version is not intended for + public distribution. Views and downloads occur in the usual way, like viewing an + MP4 rendition. + + The MP4 file becomes available for downloading when the video entity "status" + changes from "new" to "pending". The file is stored for 7 days, after which it + will be automatically deleted. + + Format of URL is `/videos/_/origin__.mp4` Where: + + - `` – Encoding bitrate in Kbps. + - `` – Video height. + + This is a premium feature, available only upon request through your manager or + support team. + """ + + origin_video_duration: Optional[int] = None + """Original video duration in milliseconds""" + + poster: Optional[str] = None + """ + Poster is your own static image which can be displayed before the video begins + playing. This is often a frame of the video or a custom title screen. + + Field contains a link to your own uploaded image. + + Also look at "screenshot" attribute. + """ + + poster_thumb: Optional[str] = None + """Field contains a link to minimized poster image. + + Original "poster" image is proportionally scaled to a size of 200 pixels in + height. + """ + + projection: Optional[str] = None + """Regulates the video format: + + - **regular** — plays the video as usual + - **vr360** — plays the video in 360 degree mode + - **vr180** — plays the video in 180 degree mode + - **vr360tb** — plays the video in 3D 360 degree mode Top-Bottom. + + Default is regular + """ + + recording_started_at: Optional[str] = None + """ + If the video was saved from a stream, then start time of the stream recording is + saved here. Format is date time in ISO 8601 + """ + + screenshot: Optional[str] = None + """A URL to the default screenshot is here. + + The image is selected from an array of all screenshots based on the + “`screenshot_id`” attribute. If you use your own "poster", the link to it will + be here too. + + Our video player uses this field to display the static image before the video + starts playing. As soon as the user hits "play" the image will go away. If you + use your own external video player, then you can use the value of this field to + set the poster/thumbnail in your player. + + Example: + + - `video_js`.poster: `api.screenshot` + - clappr.poster: `api.screenshot` + """ + + screenshot_id: Optional[int] = None + """ID of auto generated screenshots to be used for default screenshot. + + Counting from 0. A value of -1 sets the "screenshot" attribute to the URL of + your own image from the "poster" attribute. + """ + + screenshots: Optional[List[str]] = None + """Array of auto generated screenshots from the video. + + By default 5 static screenshots are taken from different places in the video. If + the video is short, there may be fewer screenshots. + + Screenshots are created automatically, so they may contain not very good frames + from the video. To use your own image look at "poster" attribute. + """ + + share_url: Optional[str] = None + """ + Custom URL or iframe displayed in the link field when a user clicks on a sharing + button in player. If empty, the link field and social network sharing is + disabled + """ + + slug: Optional[str] = None + """ + A unique alphanumeric identifier used in public URLs to retrieve and view the + video. It is unique for each video, generated randomly and set automatically by + the system. + + Format of usage in URL is _.../videos/{`client_id`}\\__{slug}/..._ + + Example: + + - Player: /videos/`12345_neAq1bYZ2` + - Manifest: /videos/`12345_neAq1bYZ2`/master.m3u8 + - Rendition: /videos/`12345_neAq1bYZ2`/`qid90v1_720`.mp4 + """ + + sprite: Optional[str] = None + """Link to picture with video storyboard. + + Image in JPG format. The picture is a set of rectangles with frames from the + video. Typically storyboard is used to show preview images when hovering the + video's timeline. + """ + + sprite_vtt: Optional[str] = None + """Storyboard in VTT format. + + This format implies an explicit indication of the timing and frame area from a + large sprite image. + """ + + status: Optional[Literal["empty", "pending", "viewable", "ready", "error"]] = None + """Video processing status: + + - empty – initial status, when video-entity is created, but video-file has not + yet been fully uploaded (TUS uploading, or downloading from an origin is not + finished yet) + - pending – video is in queue to be processed + - viewable – video has at least 1 quality and can already be viewed via a link, + but not all qualities are ready yet + - ready – video is completely ready, available for viewing with all qualities + - error – error while processing a video, look at "error" field + """ + + stream_id: Optional[int] = None + """If the video was saved from a stream, then ID of that stream is saved here""" + + views: Optional[int] = None + """ + Number of video views through the built-in HTML video player of the Streaming + Platform only. This attribute does not count views from other external players + and native OS players, so here may be less number of views than in "cdn_views". + """ diff --git a/src/gcore/types/streaming/video_create_multiple_params.py b/src/gcore/types/streaming/video_create_multiple_params.py new file mode 100644 index 00000000..dd5662a5 --- /dev/null +++ b/src/gcore/types/streaming/video_create_multiple_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import TypedDict + +from .create_video_param import CreateVideoParam +from .subtitle_base_param import SubtitleBaseParam + +__all__ = ["VideoCreateMultipleParams", "Video"] + + +class VideoCreateMultipleParams(TypedDict, total=False): + fields: str + """ + Restriction to return only the specified attributes, instead of the entire + dataset. Specify, if you need to get short response. The following fields are + available for specifying: id, name, duration, status, `created_at`, + `updated_at`, `hls_url`, screenshots, `converted_videos`, priority. Example, + ?fields=id,name,`hls_url` + """ + + videos: Iterable[Video] + + +class Video(CreateVideoParam, total=False): + subtitles: Iterable[SubtitleBaseParam] diff --git a/src/gcore/types/streaming/video_create_multiple_response.py b/src/gcore/types/streaming/video_create_multiple_response.py new file mode 100644 index 00000000..e7a82f6c --- /dev/null +++ b/src/gcore/types/streaming/video_create_multiple_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .video import Video + +__all__ = ["VideoCreateMultipleResponse"] + +VideoCreateMultipleResponse: TypeAlias = List[Video] diff --git a/src/gcore/types/streaming/video_create_params.py b/src/gcore/types/streaming/video_create_params.py new file mode 100644 index 00000000..9eab6618 --- /dev/null +++ b/src/gcore/types/streaming/video_create_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from .create_video_param import CreateVideoParam + +__all__ = ["VideoCreateParams"] + + +class VideoCreateParams(TypedDict, total=False): + video: CreateVideoParam diff --git a/src/gcore/types/streaming/video_create_response.py b/src/gcore/types/streaming/video_create_response.py new file mode 100644 index 00000000..0423bc69 --- /dev/null +++ b/src/gcore/types/streaming/video_create_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .video import Video + +__all__ = ["VideoCreateResponse"] + +VideoCreateResponse: TypeAlias = List[Video] diff --git a/src/gcore/types/streaming/video_list_names_params.py b/src/gcore/types/streaming/video_list_names_params.py new file mode 100644 index 00000000..918f5050 --- /dev/null +++ b/src/gcore/types/streaming/video_list_names_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import TypedDict + +__all__ = ["VideoListNamesParams"] + + +class VideoListNamesParams(TypedDict, total=False): + ids: Iterable[int] + """Comma-separated set of video IDs. Example, ?ids=7,17""" diff --git a/src/gcore/types/streaming/video_list_params.py b/src/gcore/types/streaming/video_list_params.py new file mode 100644 index 00000000..3d39e7e9 --- /dev/null +++ b/src/gcore/types/streaming/video_list_params.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["VideoListParams"] + + +class VideoListParams(TypedDict, total=False): + id: str + """IDs of the videos to find. + + You can specify one or more identifiers separated by commas. Example, + ?id=1,101,1001 + """ + + client_user_id: int + """Find videos where "client_user_id" meta field is equal to the search value""" + + fields: str + """ + Restriction to return only the specified attributes, instead of the entire + dataset. Specify, if you need to get short response. The following fields are + available for specifying: id, name, duration, status, `created_at`, + `updated_at`, `hls_url`, screenshots, `converted_videos`, priority, `stream_id`. + Example, ?fields=id,name,`hls_url` + """ + + page: int + """Page number. Use it to list the paginated content""" + + per_page: int + """Items per page number. Use it to list the paginated content""" + + search: str + """Aggregated search condition. + + If set, the video list is filtered by one combined SQL criterion: + + - id={s} OR slug={s} OR name like {s} + + i.e. "/videos?search=1000" returns list of videos where id=1000 or slug=1000 or + name contains "1000". + """ + + status: str + """Use it to get videos filtered by their status. Possible values: + + - empty + - pending + - viewable + - ready + - error + """ + + stream_id: int + """ + Find videos recorded from a specific stream, so for which "stream_id" field is + equal to the search value + """ diff --git a/src/gcore/types/streaming/video_update_params.py b/src/gcore/types/streaming/video_update_params.py new file mode 100644 index 00000000..72244d21 --- /dev/null +++ b/src/gcore/types/streaming/video_update_params.py @@ -0,0 +1,247 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["VideoUpdateParams"] + + +class VideoUpdateParams(TypedDict, total=False): + name: Required[str] + """Video name""" + + auto_transcribe_audio_language: Literal["disable", "auto", ""] + """Automatic creation of subtitles by transcribing the audio track. + + Values: + + - disable – Do not transcribe. + - auto – Automatically detects the activation of the option based on the + settings in your account. If generation is activated, then automatic language + detection while transcribing. + - \\ – Transcribe from specific language. Can be used to specify the exact + language spoken in the audio track, or when auto language detection fails. + Language is set by 3-letter language code according to ISO-639-2 + (bibliographic code). List of languages is available in `audio_language` + attribute of API POST /streaming/ai/transcribe . + + Example: + + ``` + auto_transcribe_audio_language: "auto" + auto_transcribe_audio_language: "ger" + ``` + + More details: + + - List of AI tasks – API + [GET /streaming/ai/tasks](/docs/api-reference/streaming/ai/get-list-of-ai-tasks) + - Add subtitles to an exist video – API + [POST /streaming/videos/{`video_id`}/subtitles](/docs/api-reference/streaming/subtitles/add-subtitle). + """ + + auto_translate_subtitles_language: Literal["disable", "default", ""] + """Automatic translation of auto-transcribed subtitles to the specified + language(s). + + Can be used both together with `auto_transcribe_audio_language` option only. + + Use it when you want to make automatic subtitles in languages other than the + original language in audio. + + Values: + + - disable – Do not translate. + - default – There are 3 default languages: eng,fre,ger + - \\ – Explicit language to translate to, or list of languages separated by a + comma. Look at list of available languages in description of AI ASR task + creation. + + If several languages are specified for translation, a separate subtitle will be + generated for each language. + + Example: + + ``` + auto_translate_subtitles_language: default + auto_translate_subtitles_language: eng,fre,ger + ``` + + Please note that subtitle translation is done separately and after + transcription. Thus separate AI-tasks are created for translation. + """ + + client_user_id: int + """Custom field where you can specify user ID in your system""" + + clip_duration_seconds: int + """ + The length of the trimmed segment to transcode, instead of the entire length of + the video. Is only used in conjunction with specifying the start of a segment. + Transcoding duration is a number in seconds. + """ + + clip_start_seconds: int + """ + If you want to transcode only a trimmed segment of a video instead of entire + length if the video, then you can provide timecodes of starting point and + duration of a segment to process. Start encoding from is a number in seconds. + """ + + custom_iframe_url: str + """Deprecated. + + Custom URL of IFrame for video player to be used in share panel in player. Auto + generated IFrame URL provided by default + """ + + description: str + """Video details; not visible to the end-users""" + + directory_id: int + """ID of the directory where the video should be uploaded. (beta)""" + + origin_http_headers: str + """Authorization HTTP request header. + + Will be used as credentials to authenticate a request to download a file + (specified in "origin_url" parameter) on an external server. + + Syntax: `Authorization: ` + + Examples: + + - "origin_http_headers": "Authorization: Basic ..." + - "origin_http_headers": "Authorization: Bearer ..." + - "origin_http_headers": "Authorization: APIKey ..." Example of usage when + downloading a file from Google Drive: + + ``` + POST https://api.gcore.com/streaming/videos + + "video": { + "name": "IBC 2024 intro.mp4", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "origin_http_headers": "Authorization: Bearer ABC" + } + ``` + """ + + origin_url: str + """ + URL to an original file which you want to copy from external storage. If + specified, system will download the file and will use it as video source for + transcoding. + """ + + poster: str + """Poster is your own static image which can be displayed before the video starts. + + After uploading the video, the system will automatically create several + screenshots (they will be stored in "screenshots" attribute) from which you can + select an default screenshot. This "poster" field is for uploading your own + image. Also use attribute "screenshot_id" to select poster as a default + screnshot. + + Attribute accepts single image as base64-encoded string + [(RFC 2397 – The "data" URL scheme)](https://www.rfc-editor.org/rfc/rfc2397). In + format: `data:[];base64,` + + MIME-types are image/jpeg, image/webp, and image/png and file sizes up to 1Mb. + + Examples: + + - `data:image/jpeg;base64,/9j/4AA...qf/2Q==` + - `data:image/png;base64,iVBORw0KGg...ggg==` + - `data:image/webp;base64,UklGRt.../DgAAAAA` + """ + + priority: int + """ + Priority allows you to adjust the urgency of processing some videos before + others in your account, if your algorithm requires it. For example, when there + are very urgent video and some regular ones that can wait in the queue. + + Value range, integer [-10..10]. -10 is the lowest down-priority, 10 is the + highest up-priority. Default priority is 0. + """ + + projection: str + """Deprecated. + + Regulates the video format: + + - **regular** — plays the video as usual + - **vr360** — plays the video in 360 degree mode + - **vr180** — plays the video in 180 degree mode + - **vr360tb** — plays the video in 3D 360 degree mode Top-Bottom. + + Default is regular + """ + + quality_set_id: int + """ + Custom quality set ID for transcoding, if transcoding is required according to + your conditions. Look at GET /`quality_sets` method + """ + + remote_poster_url: str + """ + Poster URL to download from external resource, instead of uploading via "poster" + attribute. + + It has the same restrictions as "poster" attribute. + """ + + remove_poster: bool + """Set it to true to remove poster""" + + screenshot_id: int + """Default screenshot index. + + Specify an ID from the "screenshots" array, so that the URL of the required + screenshot appears in the "screenshot" attribute as the default screenshot. By + default 5 static screenshots will be taken from different places in the video + after transcoding. If the video is short, there may be fewer screenshots. + + Counting from 0. A value of -1 sets the default screenshot to the URL of your + own image from the "poster" attribute. + + Look at "screenshot" attribute in GET /videos/{`video_id`} for details. + """ + + share_url: str + """Deprecated. + + Custom URL or iframe displayed in the link field when a user clicks on a sharing + button in player. If empty, the link field and social network sharing is + disabled + """ + + source_bitrate_limit: bool + """ + The option allows you to set the video transcoding rule so that the output + bitrate in ABR ladder is not exceeding the bitrate of the original video. + + This option is for advanced users only. + + By default `source_bitrate_limit: true` this option allows you to have the + output bitrate not more than in the original video, thus to transcode video + faster and to deliver it to end-viewers faster as well. At the same time, the + quality will be similar to the original. + + If for some reason you need more byte-space in the output quality when encoding, + you can set this option to `source_bitrate_limit: false`. Then, when + transcoding, the quality ceiling will be raised from the bitrate of the original + video to the maximum possible limit specified in our the Product Documentation. + For example, this may be needed when: + + - to improve the visual quality parameters using PSNR, SSIM, VMAF metrics, + - to improve the picture quality on dynamic scenes, + - etc. + + The option is applied only at the video creation stage and cannot be changed + later. If you want to re-transcode the video using new value, then you need to + create and upload a new video only. + """ diff --git a/src/gcore/types/streaming/videos/__init__.py b/src/gcore/types/streaming/videos/__init__.py new file mode 100644 index 00000000..e89cb741 --- /dev/null +++ b/src/gcore/types/streaming/videos/__init__.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .subtitle_create_params import SubtitleCreateParams as SubtitleCreateParams +from .subtitle_list_response import SubtitleListResponse as SubtitleListResponse +from .subtitle_update_params import SubtitleUpdateParams as SubtitleUpdateParams diff --git a/src/gcore/types/streaming/videos/subtitle_create_params.py b/src/gcore/types/streaming/videos/subtitle_create_params.py new file mode 100644 index 00000000..7ce51724 --- /dev/null +++ b/src/gcore/types/streaming/videos/subtitle_create_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from ..subtitle_base_param import SubtitleBaseParam + +__all__ = ["SubtitleCreateParams", "Body"] + + +class SubtitleCreateParams(TypedDict, total=False): + body: Required[Body] + + +class Body(SubtitleBaseParam, total=False): + pass diff --git a/src/gcore/types/streaming/videos/subtitle_list_response.py b/src/gcore/types/streaming/videos/subtitle_list_response.py new file mode 100644 index 00000000..bb683a29 --- /dev/null +++ b/src/gcore/types/streaming/videos/subtitle_list_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from ..subtitle import Subtitle + +__all__ = ["SubtitleListResponse"] + +SubtitleListResponse: TypeAlias = List[Subtitle] diff --git a/src/gcore/types/streaming/videos/subtitle_update_params.py b/src/gcore/types/streaming/videos/subtitle_update_params.py new file mode 100644 index 00000000..1806bfe7 --- /dev/null +++ b/src/gcore/types/streaming/videos/subtitle_update_params.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["SubtitleUpdateParams"] + + +class SubtitleUpdateParams(TypedDict, total=False): + video_id: Required[int] + + language: str + """3-letter language code according to ISO-639-2 (bibliographic code)""" + + name: str + """Name of subtitle file""" + + vtt: str + """Full text of subtitles/captions, with escaped "\n" ("\r") symbol of new line""" diff --git a/src/gcore/types/streaming/views.py b/src/gcore/types/streaming/views.py new file mode 100644 index 00000000..ed6b9f5d --- /dev/null +++ b/src/gcore/types/streaming/views.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["Views", "Data"] + + +class Data(BaseModel): + date: str + + type: str + + views: int + + id: Optional[int] = None + + browser: Optional[str] = None + + country: Optional[str] = None + + event: Optional[str] = None + + host: Optional[str] = None + + ip: Optional[str] = None + + os: Optional[str] = None + + platform: Optional[str] = None + + +class Views(BaseModel): + data: Optional[List[Data]] = None diff --git a/src/gcore/types/streaming/views_by_browser.py b/src/gcore/types/streaming/views_by_browser.py new file mode 100644 index 00000000..6c500eef --- /dev/null +++ b/src/gcore/types/streaming/views_by_browser.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["ViewsByBrowser", "Data"] + + +class Data(BaseModel): + browser: str + + views: int + + +class ViewsByBrowser(BaseModel): + data: Optional[List[Data]] = None diff --git a/src/gcore/types/streaming/views_by_country.py b/src/gcore/types/streaming/views_by_country.py new file mode 100644 index 00000000..32bfad49 --- /dev/null +++ b/src/gcore/types/streaming/views_by_country.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["ViewsByCountry", "Data"] + + +class Data(BaseModel): + country: str + + country_name: str + + views: int + + +class ViewsByCountry(BaseModel): + data: Optional[List[Data]] = None diff --git a/src/gcore/types/streaming/views_by_hostname.py b/src/gcore/types/streaming/views_by_hostname.py new file mode 100644 index 00000000..d71b9e95 --- /dev/null +++ b/src/gcore/types/streaming/views_by_hostname.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["ViewsByHostname", "Data"] + + +class Data(BaseModel): + host: str + + views: int + + +class ViewsByHostname(BaseModel): + data: Optional[List[Data]] = None diff --git a/src/gcore/types/streaming/views_by_operating_system.py b/src/gcore/types/streaming/views_by_operating_system.py new file mode 100644 index 00000000..4fce1e35 --- /dev/null +++ b/src/gcore/types/streaming/views_by_operating_system.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["ViewsByOperatingSystem", "Data"] + + +class Data(BaseModel): + os: str + + views: int + + +class ViewsByOperatingSystem(BaseModel): + data: Optional[List[Data]] = None diff --git a/src/gcore/types/streaming/views_by_referer.py b/src/gcore/types/streaming/views_by_referer.py new file mode 100644 index 00000000..0ba51d1a --- /dev/null +++ b/src/gcore/types/streaming/views_by_referer.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["ViewsByReferer", "Data"] + + +class Data(BaseModel): + embed_url: str + + views: int + + +class ViewsByReferer(BaseModel): + data: Optional[List[Data]] = None diff --git a/src/gcore/types/streaming/views_by_region.py b/src/gcore/types/streaming/views_by_region.py new file mode 100644 index 00000000..0a789153 --- /dev/null +++ b/src/gcore/types/streaming/views_by_region.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["ViewsByRegion", "Data"] + + +class Data(BaseModel): + region: str + + region_name: str + + views: int + + +class ViewsByRegion(BaseModel): + data: Optional[List[Data]] = None diff --git a/src/gcore/types/streaming/views_heatmap.py b/src/gcore/types/streaming/views_heatmap.py new file mode 100644 index 00000000..819d76bd --- /dev/null +++ b/src/gcore/types/streaming/views_heatmap.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["ViewsHeatmap", "Data"] + + +class Data(BaseModel): + viewers: int + + seconds: Optional[int] = None + + time: Optional[str] = None + + +class ViewsHeatmap(BaseModel): + data: Optional[List[Data]] = None diff --git a/src/gcore/types/streaming/vod_statistics_series.py b/src/gcore/types/streaming/vod_statistics_series.py new file mode 100644 index 00000000..7b268b3f --- /dev/null +++ b/src/gcore/types/streaming/vod_statistics_series.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["VodStatisticsSeries", "VodStatisticsSeriesItem", "VodStatisticsSeriesItemMetrics"] + + +class VodStatisticsSeriesItemMetrics(BaseModel): + vod: List[int] + + +class VodStatisticsSeriesItem(BaseModel): + client: int + + metrics: VodStatisticsSeriesItemMetrics + + +VodStatisticsSeries: TypeAlias = List[VodStatisticsSeriesItem] diff --git a/src/gcore/types/streaming/vod_total_stream_duration_series.py b/src/gcore/types/streaming/vod_total_stream_duration_series.py new file mode 100644 index 00000000..28dc7dda --- /dev/null +++ b/src/gcore/types/streaming/vod_total_stream_duration_series.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import TypeAlias + +from ..._models import BaseModel + +__all__ = ["VodTotalStreamDurationSeries", "VodTotalStreamDurationSeriesItem"] + + +class VodTotalStreamDurationSeriesItem(BaseModel): + client: int + + duration: int + """count of minutes""" + + client_user_id: Optional[int] = None + + stream_id: Optional[str] = None + + +VodTotalStreamDurationSeries: TypeAlias = List[VodTotalStreamDurationSeriesItem] diff --git a/src/gcore/types/waap/__init__.py b/src/gcore/types/waap/__init__.py new file mode 100644 index 00000000..b90f2d8b --- /dev/null +++ b/src/gcore/types/waap/__init__.py @@ -0,0 +1,60 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .waap_tag import WaapTag as WaapTag +from .waap_ip_info import WaapIPInfo as WaapIPInfo +from .waap_top_url import WaapTopURL as WaapTopURL +from .waap_rule_set import WaapRuleSet as WaapRuleSet +from .tag_list_params import TagListParams as TagListParams +from .waap_policy_mode import WaapPolicyMode as WaapPolicyMode +from .waap_top_session import WaapTopSession as WaapTopSession +from .waap_insight_type import WaapInsightType as WaapInsightType +from .waap_organization import WaapOrganization as WaapOrganization +from .domain_list_params import DomainListParams as DomainListParams +from .waap_statistic_item import WaapStatisticItem as WaapStatisticItem +from .waap_summary_domain import WaapSummaryDomain as WaapSummaryDomain +from .waap_top_user_agent import WaapTopUserAgent as WaapTopUserAgent +from .domain_update_params import DomainUpdateParams as DomainUpdateParams +from .waap_custom_page_set import WaapCustomPageSet as WaapCustomPageSet +from .waap_detailed_domain import WaapDetailedDomain as WaapDetailedDomain +from .waap_ip_country_attack import WaapIPCountryAttack as WaapIPCountryAttack +from .waap_statistics_series import WaapStatisticsSeries as WaapStatisticsSeries +from .waap_ip_ddos_info_model import WaapIPDDOSInfoModel as WaapIPDDOSInfoModel +from .waap_time_series_attack import WaapTimeSeriesAttack as WaapTimeSeriesAttack +from .organization_list_params import OrganizationListParams as OrganizationListParams +from .waap_custom_page_preview import WaapCustomPagePreview as WaapCustomPagePreview +from .waap_domain_api_settings import WaapDomainAPISettings as WaapDomainAPISettings +from .insight_list_types_params import InsightListTypesParams as InsightListTypesParams +from .waap_domain_ddos_settings import WaapDomainDDOSSettings as WaapDomainDDOSSettings +from .ip_info_get_ip_info_params import IPInfoGetIPInfoParams as IPInfoGetIPInfoParams +from .waap_domain_settings_model import WaapDomainSettingsModel as WaapDomainSettingsModel +from .waap_rule_blocked_requests import WaapRuleBlockedRequests as WaapRuleBlockedRequests +from .custom_page_set_list_params import CustomPageSetListParams as CustomPageSetListParams +from .ip_info_get_top_urls_params import IPInfoGetTopURLsParams as IPInfoGetTopURLsParams +from .custom_page_set_create_params import CustomPageSetCreateParams as CustomPageSetCreateParams +from .custom_page_set_update_params import CustomPageSetUpdateParams as CustomPageSetUpdateParams +from .ip_info_get_top_urls_response import IPInfoGetTopURLsResponse as IPInfoGetTopURLsResponse +from .waap_advanced_rule_descriptor import WaapAdvancedRuleDescriptor as WaapAdvancedRuleDescriptor +from .custom_page_set_preview_params import CustomPageSetPreviewParams as CustomPageSetPreviewParams +from .domain_list_rule_sets_response import DomainListRuleSetsResponse as DomainListRuleSetsResponse +from .statistic_get_usage_series_params import StatisticGetUsageSeriesParams as StatisticGetUsageSeriesParams +from .ip_info_get_top_user_agents_params import IPInfoGetTopUserAgentsParams as IPInfoGetTopUserAgentsParams +from .waap_advanced_rule_descriptor_list import WaapAdvancedRuleDescriptorList as WaapAdvancedRuleDescriptorList +from .waap_get_account_overview_response import WaapGetAccountOverviewResponse as WaapGetAccountOverviewResponse +from .ip_info_get_blocked_requests_params import IPInfoGetBlockedRequestsParams as IPInfoGetBlockedRequestsParams +from .ip_info_get_top_user_agents_response import IPInfoGetTopUserAgentsResponse as IPInfoGetTopUserAgentsResponse +from .ip_info_get_top_user_sessions_params import IPInfoGetTopUserSessionsParams as IPInfoGetTopUserSessionsParams +from .ip_info_get_attack_time_series_params import IPInfoGetAttackTimeSeriesParams as IPInfoGetAttackTimeSeriesParams +from .ip_info_get_blocked_requests_response import IPInfoGetBlockedRequestsResponse as IPInfoGetBlockedRequestsResponse +from .ip_info_get_ddos_attack_series_params import IPInfoGetDDOSAttackSeriesParams as IPInfoGetDDOSAttackSeriesParams +from .ip_info_get_top_user_sessions_response import IPInfoGetTopUserSessionsResponse as IPInfoGetTopUserSessionsResponse +from .ip_info_list_attacked_countries_params import ( + IPInfoListAttackedCountriesParams as IPInfoListAttackedCountriesParams, +) +from .ip_info_get_attack_time_series_response import ( + IPInfoGetAttackTimeSeriesResponse as IPInfoGetAttackTimeSeriesResponse, +) +from .ip_info_list_attacked_countries_response import ( + IPInfoListAttackedCountriesResponse as IPInfoListAttackedCountriesResponse, +) diff --git a/src/gcore/types/waap/custom_page_set_create_params.py b/src/gcore/types/waap/custom_page_set_create_params.py new file mode 100644 index 00000000..89636eb5 --- /dev/null +++ b/src/gcore/types/waap/custom_page_set_create_params.py @@ -0,0 +1,142 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Required, TypedDict + +__all__ = [ + "CustomPageSetCreateParams", + "Block", + "BlockCsrf", + "Captcha", + "CookieDisabled", + "Handshake", + "JavascriptDisabled", +] + + +class CustomPageSetCreateParams(TypedDict, total=False): + name: Required[str] + """Name of the custom page set""" + + block: Optional[Block] + + block_csrf: Optional[BlockCsrf] + + captcha: Optional[Captcha] + + cookie_disabled: Optional[CookieDisabled] + + domains: Optional[Iterable[int]] + """List of domain IDs that are associated with this page set""" + + handshake: Optional[Handshake] + + javascript_disabled: Optional[JavascriptDisabled] + + +class Block(TypedDict, total=False): + enabled: Required[bool] + """Indicates whether the custom custom page is active or inactive""" + + header: str + """The text to display in the header of the custom page""" + + logo: str + """ + Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + """ + + text: str + """The text to display in the body of the custom page""" + + title: str + """The text to display in the title of the custom page""" + + +class BlockCsrf(TypedDict, total=False): + enabled: Required[bool] + """Indicates whether the custom custom page is active or inactive""" + + header: str + """The text to display in the header of the custom page""" + + logo: str + """ + Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + """ + + text: str + """The text to display in the body of the custom page""" + + title: str + """The text to display in the title of the custom page""" + + +class Captcha(TypedDict, total=False): + enabled: Required[bool] + """Indicates whether the custom custom page is active or inactive""" + + error: str + """Error message""" + + header: str + """The text to display in the header of the custom page""" + + logo: str + """ + Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + """ + + text: str + """The text to display in the body of the custom page""" + + title: str + """The text to display in the title of the custom page""" + + +class CookieDisabled(TypedDict, total=False): + enabled: Required[bool] + """Indicates whether the custom custom page is active or inactive""" + + header: str + """The text to display in the header of the custom page""" + + text: str + """The text to display in the body of the custom page""" + + +class Handshake(TypedDict, total=False): + enabled: Required[bool] + """Indicates whether the custom custom page is active or inactive""" + + header: str + """The text to display in the header of the custom page""" + + logo: str + """ + Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + """ + + title: str + """The text to display in the title of the custom page""" + + +class JavascriptDisabled(TypedDict, total=False): + enabled: Required[bool] + """Indicates whether the custom custom page is active or inactive""" + + header: str + """The text to display in the header of the custom page""" + + text: str + """The text to display in the body of the custom page""" diff --git a/src/gcore/types/waap/custom_page_set_list_params.py b/src/gcore/types/waap/custom_page_set_list_params.py new file mode 100644 index 00000000..cad46fcc --- /dev/null +++ b/src/gcore/types/waap/custom_page_set_list_params.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, TypedDict + +__all__ = ["CustomPageSetListParams"] + + +class CustomPageSetListParams(TypedDict, total=False): + ids: Iterable[int] + """Filter page sets based on their IDs""" + + limit: int + """Number of items to return""" + + name: str + """Filter page sets based on their name. Supports '\\**' as a wildcard character""" + + offset: int + """Number of items to skip""" + + ordering: Literal["name", "-name", "id", "-id"] + """Sort the response by given field.""" diff --git a/src/gcore/types/waap/custom_page_set_preview_params.py b/src/gcore/types/waap/custom_page_set_preview_params.py new file mode 100644 index 00000000..158b1a3a --- /dev/null +++ b/src/gcore/types/waap/custom_page_set_preview_params.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["CustomPageSetPreviewParams"] + + +class CustomPageSetPreviewParams(TypedDict, total=False): + page_type: Required[ + Literal[ + "block.html", + "block_csrf.html", + "captcha.html", + "cookieDisabled.html", + "handshake.html", + "javascriptDisabled.html", + ] + ] + """The type of the custom page""" + + error: Optional[str] + """Error message""" + + header: Optional[str] + """The text to display in the header of the custom page""" + + logo: Optional[str] + """ + Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + """ + + text: Optional[str] + """The text to display in the body of the custom page""" + + title: Optional[str] + """The text to display in the title of the custom page""" diff --git a/src/gcore/types/waap/custom_page_set_update_params.py b/src/gcore/types/waap/custom_page_set_update_params.py new file mode 100644 index 00000000..44279a3e --- /dev/null +++ b/src/gcore/types/waap/custom_page_set_update_params.py @@ -0,0 +1,142 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Required, TypedDict + +__all__ = [ + "CustomPageSetUpdateParams", + "Block", + "BlockCsrf", + "Captcha", + "CookieDisabled", + "Handshake", + "JavascriptDisabled", +] + + +class CustomPageSetUpdateParams(TypedDict, total=False): + block: Optional[Block] + + block_csrf: Optional[BlockCsrf] + + captcha: Optional[Captcha] + + cookie_disabled: Optional[CookieDisabled] + + domains: Optional[Iterable[int]] + """List of domain IDs that are associated with this page set""" + + handshake: Optional[Handshake] + + javascript_disabled: Optional[JavascriptDisabled] + + name: Optional[str] + """Name of the custom page set""" + + +class Block(TypedDict, total=False): + enabled: Required[bool] + """Indicates whether the custom custom page is active or inactive""" + + header: str + """The text to display in the header of the custom page""" + + logo: str + """ + Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + """ + + text: str + """The text to display in the body of the custom page""" + + title: str + """The text to display in the title of the custom page""" + + +class BlockCsrf(TypedDict, total=False): + enabled: Required[bool] + """Indicates whether the custom custom page is active or inactive""" + + header: str + """The text to display in the header of the custom page""" + + logo: str + """ + Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + """ + + text: str + """The text to display in the body of the custom page""" + + title: str + """The text to display in the title of the custom page""" + + +class Captcha(TypedDict, total=False): + enabled: Required[bool] + """Indicates whether the custom custom page is active or inactive""" + + error: str + """Error message""" + + header: str + """The text to display in the header of the custom page""" + + logo: str + """ + Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + """ + + text: str + """The text to display in the body of the custom page""" + + title: str + """The text to display in the title of the custom page""" + + +class CookieDisabled(TypedDict, total=False): + enabled: Required[bool] + """Indicates whether the custom custom page is active or inactive""" + + header: str + """The text to display in the header of the custom page""" + + text: str + """The text to display in the body of the custom page""" + + +class Handshake(TypedDict, total=False): + enabled: Required[bool] + """Indicates whether the custom custom page is active or inactive""" + + header: str + """The text to display in the header of the custom page""" + + logo: str + """ + Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + """ + + title: str + """The text to display in the title of the custom page""" + + +class JavascriptDisabled(TypedDict, total=False): + enabled: Required[bool] + """Indicates whether the custom custom page is active or inactive""" + + header: str + """The text to display in the header of the custom page""" + + text: str + """The text to display in the body of the custom page""" diff --git a/src/gcore/types/waap/domain_list_params.py b/src/gcore/types/waap/domain_list_params.py new file mode 100644 index 00000000..767d4eaa --- /dev/null +++ b/src/gcore/types/waap/domain_list_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Literal, TypedDict + +__all__ = ["DomainListParams"] + + +class DomainListParams(TypedDict, total=False): + ids: Iterable[int] + """Filter domains based on their IDs""" + + limit: int + """Number of items to return""" + + name: str + """Filter domains based on the domain name. Supports '\\**' as a wildcard character""" + + offset: int + """Number of items to skip""" + + ordering: Literal["id", "name", "status", "created_at", "-id", "-name", "-status", "-created_at"] + """Sort the response by given field.""" + + status: Literal["active", "bypass", "monitor", "locked"] + """Filter domains based on the domain status""" diff --git a/src/gcore/types/waap/domain_list_rule_sets_response.py b/src/gcore/types/waap/domain_list_rule_sets_response.py new file mode 100644 index 00000000..3a82e138 --- /dev/null +++ b/src/gcore/types/waap/domain_list_rule_sets_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .waap_rule_set import WaapRuleSet + +__all__ = ["DomainListRuleSetsResponse"] + +DomainListRuleSetsResponse: TypeAlias = List[WaapRuleSet] diff --git a/src/gcore/types/waap/domain_update_params.py b/src/gcore/types/waap/domain_update_params.py new file mode 100644 index 00000000..a445eddf --- /dev/null +++ b/src/gcore/types/waap/domain_update_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["DomainUpdateParams"] + + +class DomainUpdateParams(TypedDict, total=False): + status: Required[Literal["active", "monitor"]] + """The current status of the domain""" diff --git a/src/gcore/types/waap/domains/__init__.py b/src/gcore/types/waap/domains/__init__.py new file mode 100644 index 00000000..905ada2a --- /dev/null +++ b/src/gcore/types/waap/domains/__init__.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .waap_insight import WaapInsight as WaapInsight +from .waap_task_id import WaapTaskID as WaapTaskID +from .waap_api_path import WaapAPIPath as WaapAPIPath +from .waap_ddos_info import WaapDDOSInfo as WaapDDOSInfo +from .waap_custom_rule import WaapCustomRule as WaapCustomRule +from .waap_ddos_attack import WaapDDOSAttack as WaapDDOSAttack +from .waap_advanced_rule import WaapAdvancedRule as WaapAdvancedRule +from .waap_firewall_rule import WaapFirewallRule as WaapFirewallRule +from .api_path_group_list import APIPathGroupList as APIPathGroupList +from .insight_list_params import InsightListParams as InsightListParams +from .api_path_list_params import APIPathListParams as APIPathListParams +from .waap_api_scan_result import WaapAPIScanResult as WaapAPIScanResult +from .waap_insight_silence import WaapInsightSilence as WaapInsightSilence +from .waap_request_details import WaapRequestDetails as WaapRequestDetails +from .waap_request_summary import WaapRequestSummary as WaapRequestSummary +from .waap_traffic_metrics import WaapTrafficMetrics as WaapTrafficMetrics +from .setting_update_params import SettingUpdateParams as SettingUpdateParams +from .waap_count_statistics import WaapCountStatistics as WaapCountStatistics +from .waap_event_statistics import WaapEventStatistics as WaapEventStatistics +from .api_path_create_params import APIPathCreateParams as APIPathCreateParams +from .api_path_update_params import APIPathUpdateParams as APIPathUpdateParams +from .insight_replace_params import InsightReplaceParams as InsightReplaceParams +from .custom_rule_list_params import CustomRuleListParams as CustomRuleListParams +from .waap_blocked_statistics import WaapBlockedStatistics as WaapBlockedStatistics +from .advanced_rule_list_params import AdvancedRuleListParams as AdvancedRuleListParams +from .custom_rule_create_params import CustomRuleCreateParams as CustomRuleCreateParams +from .custom_rule_update_params import CustomRuleUpdateParams as CustomRuleUpdateParams +from .firewall_rule_list_params import FirewallRuleListParams as FirewallRuleListParams +from .advanced_rule_create_params import AdvancedRuleCreateParams as AdvancedRuleCreateParams +from .advanced_rule_update_params import AdvancedRuleUpdateParams as AdvancedRuleUpdateParams +from .firewall_rule_create_params import FirewallRuleCreateParams as FirewallRuleCreateParams +from .firewall_rule_update_params import FirewallRuleUpdateParams as FirewallRuleUpdateParams +from .insight_silence_list_params import InsightSilenceListParams as InsightSilenceListParams +from .waap_api_discovery_settings import WaapAPIDiscoverySettings as WaapAPIDiscoverySettings +from .insight_silence_create_params import InsightSilenceCreateParams as InsightSilenceCreateParams +from .insight_silence_update_params import InsightSilenceUpdateParams as InsightSilenceUpdateParams +from .statistic_get_ddos_info_params import StatisticGetDDOSInfoParams as StatisticGetDDOSInfoParams +from .statistic_get_ddos_attacks_params import StatisticGetDDOSAttacksParams as StatisticGetDDOSAttacksParams +from .custom_rule_delete_multiple_params import CustomRuleDeleteMultipleParams as CustomRuleDeleteMultipleParams +from .api_discovery_upload_openapi_params import APIDiscoveryUploadOpenAPIParams as APIDiscoveryUploadOpenAPIParams +from .statistic_get_traffic_series_params import StatisticGetTrafficSeriesParams as StatisticGetTrafficSeriesParams +from .api_discovery_update_settings_params import APIDiscoveryUpdateSettingsParams as APIDiscoveryUpdateSettingsParams +from .firewall_rule_delete_multiple_params import FirewallRuleDeleteMultipleParams as FirewallRuleDeleteMultipleParams +from .statistic_get_requests_series_params import StatisticGetRequestsSeriesParams as StatisticGetRequestsSeriesParams +from .statistic_get_traffic_series_response import ( + StatisticGetTrafficSeriesResponse as StatisticGetTrafficSeriesResponse, +) +from .api_discovery_list_scan_results_params import ( + APIDiscoveryListScanResultsParams as APIDiscoveryListScanResultsParams, +) +from .statistic_get_events_aggregated_params import ( + StatisticGetEventsAggregatedParams as StatisticGetEventsAggregatedParams, +) diff --git a/src/gcore/types/waap/domains/advanced_rule_create_params.py b/src/gcore/types/waap/domains/advanced_rule_create_params.py new file mode 100644 index 00000000..cabe49cb --- /dev/null +++ b/src/gcore/types/waap/domains/advanced_rule_create_params.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["AdvancedRuleCreateParams", "Action", "ActionBlock", "ActionTag"] + + +class AdvancedRuleCreateParams(TypedDict, total=False): + action: Required[Action] + """The action that the rule takes when triggered. + + Only one action can be set per rule. + """ + + enabled: Required[bool] + """Whether or not the rule is enabled""" + + name: Required[str] + """The name assigned to the rule""" + + source: Required[str] + """A CEL syntax expression that contains the rule's conditions. + + Allowed objects are: request, whois, session, response, tags, + `user_defined_tags`, `user_agent`, `client_data`. + + More info can be found here: + https://gcore.com/docs/waap/waap-rules/advanced-rules + """ + + description: str + """The description assigned to the rule""" + + phase: Optional[Literal["access", "header_filter", "body_filter"]] + """The WAAP request/response phase for applying the rule. Default is "access". + + The "access" phase is responsible for modifying the request before it is sent to + the origin server. + + The "header_filter" phase is responsible for modifying the HTTP headers of a + response before they are sent back to the client. + + The "body_filter" phase is responsible for modifying the body of a response + before it is sent back to the client. + """ + + +class ActionBlock(TypedDict, total=False): + """ + WAAP block action behavior could be configured with response status code and action duration. + """ + + action_duration: str + """How long a rule's block action will apply to subsequent requests. + + Can be specified in seconds or by using a numeral followed by 's', 'm', 'h', or + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. + """ + + status_code: Literal[403, 405, 418, 429] + """A custom HTTP status code that the WAAP returns if a rule blocks a request""" + + +class ActionTag(TypedDict, total=False): + """WAAP tag action gets a list of tags to tag the request scope with""" + + tags: Required[SequenceNotStr[str]] + """The list of user defined tags to tag the request with""" + + +class Action(TypedDict, total=False): + """The action that the rule takes when triggered. + + Only one action can be set per rule. + """ + + allow: Dict[str, object] + """The WAAP allows the request""" + + block: ActionBlock + """ + WAAP block action behavior could be configured with response status code and + action duration. + """ + + captcha: Dict[str, object] + """The WAAP presents the user with a captcha""" + + handshake: Dict[str, object] + """The WAAP performs automatic browser validation""" + + monitor: Dict[str, object] + """The WAAP monitors the request but takes no action""" + + tag: ActionTag + """WAAP tag action gets a list of tags to tag the request scope with""" diff --git a/src/gcore/types/waap/domains/advanced_rule_list_params.py b/src/gcore/types/waap/domains/advanced_rule_list_params.py new file mode 100644 index 00000000..301d3eb4 --- /dev/null +++ b/src/gcore/types/waap/domains/advanced_rule_list_params.py @@ -0,0 +1,59 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["AdvancedRuleListParams"] + + +class AdvancedRuleListParams(TypedDict, total=False): + action: Literal["allow", "block", "captcha", "handshake", "monitor", "tag"] + """Filter to refine results by specific actions""" + + description: str + """Filter rules based on their description. Supports '\\**' as a wildcard character.""" + + enabled: bool + """Filter rules based on their active status""" + + limit: int + """Number of items to return""" + + name: str + """Filter rules based on their name. Supports '\\**' as a wildcard character.""" + + offset: int + """Number of items to skip""" + + ordering: Optional[ + Literal[ + "id", + "name", + "description", + "enabled", + "action", + "phase", + "-id", + "-name", + "-description", + "-enabled", + "-action", + "-phase", + ] + ] + """Determine the field to order results by""" + + phase: Literal["access", "header_filter", "body_filter"] + """Filter rules based on the WAAP request/response phase for applying the rule. + + The "access" phase is responsible for modifying the request before it is sent to + the origin server. + + The "header_filter" phase is responsible for modifying the HTTP headers of a + response before they are sent back to the client. + + The "body_filter" phase is responsible for modifying the body of a response + before it is sent back to the client. + """ diff --git a/src/gcore/types/waap/domains/advanced_rule_update_params.py b/src/gcore/types/waap/domains/advanced_rule_update_params.py new file mode 100644 index 00000000..9ba318f0 --- /dev/null +++ b/src/gcore/types/waap/domains/advanced_rule_update_params.py @@ -0,0 +1,99 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["AdvancedRuleUpdateParams", "Action", "ActionBlock", "ActionTag"] + + +class AdvancedRuleUpdateParams(TypedDict, total=False): + domain_id: Required[int] + """The domain ID""" + + action: Optional[Action] + """The action that a WAAP rule takes when triggered.""" + + description: Optional[str] + """The description assigned to the rule""" + + enabled: Optional[bool] + """Whether or not the rule is enabled""" + + name: Optional[str] + """The name assigned to the rule""" + + phase: Optional[Literal["access", "header_filter", "body_filter"]] + """The WAAP request/response phase for applying the rule. + + The "access" phase is responsible for modifying the request before it is sent to + the origin server. + + The "header_filter" phase is responsible for modifying the HTTP headers of a + response before they are sent back to the client. + + The "body_filter" phase is responsible for modifying the body of a response + before it is sent back to the client. + """ + + source: Optional[str] + """A CEL syntax expression that contains the rule's conditions. + + Allowed objects are: request, whois, session, response, tags, + `user_defined_tags`, `user_agent`, `client_data`. + + More info can be found here: + https://gcore.com/docs/waap/waap-rules/advanced-rules + """ + + +class ActionBlock(TypedDict, total=False): + """ + WAAP block action behavior could be configured with response status code and action duration. + """ + + action_duration: str + """How long a rule's block action will apply to subsequent requests. + + Can be specified in seconds or by using a numeral followed by 's', 'm', 'h', or + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. + """ + + status_code: Literal[403, 405, 418, 429] + """A custom HTTP status code that the WAAP returns if a rule blocks a request""" + + +class ActionTag(TypedDict, total=False): + """WAAP tag action gets a list of tags to tag the request scope with""" + + tags: Required[SequenceNotStr[str]] + """The list of user defined tags to tag the request with""" + + +class Action(TypedDict, total=False): + """The action that a WAAP rule takes when triggered.""" + + allow: Dict[str, object] + """The WAAP allows the request""" + + block: ActionBlock + """ + WAAP block action behavior could be configured with response status code and + action duration. + """ + + captcha: Dict[str, object] + """The WAAP presents the user with a captcha""" + + handshake: Dict[str, object] + """The WAAP performs automatic browser validation""" + + monitor: Dict[str, object] + """The WAAP monitors the request but takes no action""" + + tag: ActionTag + """WAAP tag action gets a list of tags to tag the request scope with""" diff --git a/src/gcore/types/waap/domains/api_discovery_list_scan_results_params.py b/src/gcore/types/waap/domains/api_discovery_list_scan_results_params.py new file mode 100644 index 00000000..28b05065 --- /dev/null +++ b/src/gcore/types/waap/domains/api_discovery_list_scan_results_params.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["APIDiscoveryListScanResultsParams"] + + +class APIDiscoveryListScanResultsParams(TypedDict, total=False): + limit: int + """Number of items to return""" + + message: Optional[str] + """Filter by the message of the scan. Supports '\\**' as a wildcard character""" + + offset: int + """Number of items to skip""" + + ordering: Literal[ + "id", + "type", + "start_time", + "end_time", + "status", + "message", + "-id", + "-type", + "-start_time", + "-end_time", + "-status", + "-message", + ] + """Sort the response by given field.""" + + status: Optional[Literal["SUCCESS", "FAILURE", "IN_PROGRESS"]] + """Filter by the status of the scan""" + + type: Optional[Literal["TRAFFIC_SCAN", "API_DESCRIPTION_FILE_SCAN"]] + """Filter by the path of the scan type""" diff --git a/src/gcore/types/waap/domains/api_discovery_update_settings_params.py b/src/gcore/types/waap/domains/api_discovery_update_settings_params.py new file mode 100644 index 00000000..3274d926 --- /dev/null +++ b/src/gcore/types/waap/domains/api_discovery_update_settings_params.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["APIDiscoveryUpdateSettingsParams"] + + +class APIDiscoveryUpdateSettingsParams(TypedDict, total=False): + description_file_location: Annotated[Optional[str], PropertyInfo(alias="descriptionFileLocation")] + """The URL of the API description file. + + This will be periodically scanned if `descriptionFileScanEnabled` is enabled. + Supported formats are YAML and JSON, and it must adhere to OpenAPI versions 2, + 3, or 3.1. + """ + + description_file_scan_enabled: Annotated[Optional[bool], PropertyInfo(alias="descriptionFileScanEnabled")] + """Indicates if periodic scan of the description file is enabled""" + + description_file_scan_interval_hours: Annotated[ + Optional[int], PropertyInfo(alias="descriptionFileScanIntervalHours") + ] + """The interval in hours for scanning the description file""" + + traffic_scan_enabled: Annotated[Optional[bool], PropertyInfo(alias="trafficScanEnabled")] + """Indicates if traffic scan is enabled""" + + traffic_scan_interval_hours: Annotated[Optional[int], PropertyInfo(alias="trafficScanIntervalHours")] + """The interval in hours for scanning the traffic""" diff --git a/src/gcore/types/waap/domains/api_discovery_upload_openapi_params.py b/src/gcore/types/waap/domains/api_discovery_upload_openapi_params.py new file mode 100644 index 00000000..0bf87add --- /dev/null +++ b/src/gcore/types/waap/domains/api_discovery_upload_openapi_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["APIDiscoveryUploadOpenAPIParams"] + + +class APIDiscoveryUploadOpenAPIParams(TypedDict, total=False): + file_data: Required[str] + """Base64 representation of the description file. + + Supported formats are YAML and JSON, and it must adhere to OpenAPI versions 2, + 3, or 3.1. + """ + + file_name: Required[str] + """The name of the file""" diff --git a/src/gcore/types/waap/domains/api_path_create_params.py b/src/gcore/types/waap/domains/api_path_create_params.py new file mode 100644 index 00000000..b8c370d3 --- /dev/null +++ b/src/gcore/types/waap/domains/api_path_create_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["APIPathCreateParams"] + + +class APIPathCreateParams(TypedDict, total=False): + http_scheme: Required[Literal["HTTP", "HTTPS"]] + """The different HTTP schemes an API path can have""" + + method: Required[Literal["GET", "POST", "PUT", "PATCH", "DELETE", "TRACE", "HEAD", "OPTIONS"]] + """The different methods an API path can have""" + + path: Required[str] + """ + The API path, locations that are saved for resource IDs will be put in curly + brackets + """ + + api_groups: SequenceNotStr[str] + + api_version: str + + tags: SequenceNotStr[str] diff --git a/src/gcore/types/waap/domains/api_path_group_list.py b/src/gcore/types/waap/domains/api_path_group_list.py new file mode 100644 index 00000000..3990cfeb --- /dev/null +++ b/src/gcore/types/waap/domains/api_path_group_list.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ...._models import BaseModel + +__all__ = ["APIPathGroupList"] + + +class APIPathGroupList(BaseModel): + """Response model for the API path groups""" + + api_path_groups: List[str] + """An array of api groups associated with the API path""" diff --git a/src/gcore/types/waap/domains/api_path_list_params.py b/src/gcore/types/waap/domains/api_path_list_params.py new file mode 100644 index 00000000..34ef9fe5 --- /dev/null +++ b/src/gcore/types/waap/domains/api_path_list_params.py @@ -0,0 +1,64 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["APIPathListParams"] + + +class APIPathListParams(TypedDict, total=False): + api_group: Optional[str] + """Filter by the API group associated with the API path""" + + api_version: Optional[str] + """Filter by the API version""" + + http_scheme: Optional[Literal["HTTP", "HTTPS"]] + """Filter by the HTTP version of the API path""" + + ids: Optional[SequenceNotStr[str]] + """Filter by the path ID""" + + limit: int + """Number of items to return""" + + method: Optional[Literal["GET", "POST", "PUT", "PATCH", "DELETE", "TRACE", "HEAD", "OPTIONS"]] + """Filter by the API RESTful method""" + + offset: int + """Number of items to skip""" + + ordering: Literal[ + "id", + "path", + "method", + "api_version", + "http_scheme", + "first_detected", + "last_detected", + "status", + "source", + "-id", + "-path", + "-method", + "-api_version", + "-http_scheme", + "-first_detected", + "-last_detected", + "-status", + "-source", + ] + """Sort the response by given field.""" + + path: Optional[str] + """Filter by the path. Supports '\\**' as a wildcard character""" + + source: Optional[Literal["API_DESCRIPTION_FILE", "TRAFFIC_SCAN", "USER_DEFINED"]] + """Filter by the source of the discovered API""" + + status: Optional[List[Literal["CONFIRMED_API", "POTENTIAL_API", "NOT_API", "DELISTED_API"]]] + """Filter by the status of the discovered API path""" diff --git a/src/gcore/types/waap/domains/api_path_update_params.py b/src/gcore/types/waap/domains/api_path_update_params.py new file mode 100644 index 00000000..18c1927f --- /dev/null +++ b/src/gcore/types/waap/domains/api_path_update_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["APIPathUpdateParams"] + + +class APIPathUpdateParams(TypedDict, total=False): + domain_id: Required[int] + """The domain ID""" + + api_groups: SequenceNotStr[str] + + path: str + """The updated API path. + + When updating the path, variables can be renamed, path parts can be converted to + variables and vice versa. + """ + + status: Literal["CONFIRMED_API", "POTENTIAL_API", "NOT_API", "DELISTED_API"] + """The different statuses an API path can have""" + + tags: SequenceNotStr[str] diff --git a/src/gcore/types/waap/domains/custom_rule_create_params.py b/src/gcore/types/waap/domains/custom_rule_create_params.py new file mode 100644 index 00000000..38d1fcaf --- /dev/null +++ b/src/gcore/types/waap/domains/custom_rule_create_params.py @@ -0,0 +1,427 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = [ + "CustomRuleCreateParams", + "Action", + "ActionBlock", + "ActionTag", + "Condition", + "ConditionContentType", + "ConditionCountry", + "ConditionFileExtension", + "ConditionHeader", + "ConditionHeaderExists", + "ConditionHTTPMethod", + "ConditionIP", + "ConditionIPRange", + "ConditionOrganization", + "ConditionOwnerTypes", + "ConditionRequestRate", + "ConditionResponseHeader", + "ConditionResponseHeaderExists", + "ConditionSessionRequestCount", + "ConditionTags", + "ConditionURL", + "ConditionUserAgent", + "ConditionUserDefinedTags", +] + + +class CustomRuleCreateParams(TypedDict, total=False): + action: Required[Action] + """The action that the rule takes when triggered. + + Only one action can be set per rule. + """ + + conditions: Required[Iterable[Condition]] + """The conditions required for the WAAP engine to trigger the rule. + + Rules may have between 1 and 5 conditions. All conditions must pass for the rule + to trigger + """ + + enabled: Required[bool] + """Whether or not the rule is enabled""" + + name: Required[str] + """The name assigned to the rule""" + + description: str + """The description assigned to the rule""" + + +class ActionBlock(TypedDict, total=False): + """ + WAAP block action behavior could be configured with response status code and action duration. + """ + + action_duration: str + """How long a rule's block action will apply to subsequent requests. + + Can be specified in seconds or by using a numeral followed by 's', 'm', 'h', or + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. + """ + + status_code: Literal[403, 405, 418, 429] + """A custom HTTP status code that the WAAP returns if a rule blocks a request""" + + +class ActionTag(TypedDict, total=False): + """WAAP tag action gets a list of tags to tag the request scope with""" + + tags: Required[SequenceNotStr[str]] + """The list of user defined tags to tag the request with""" + + +class Action(TypedDict, total=False): + """The action that the rule takes when triggered. + + Only one action can be set per rule. + """ + + allow: Dict[str, object] + """The WAAP allows the request""" + + block: ActionBlock + """ + WAAP block action behavior could be configured with response status code and + action duration. + """ + + captcha: Dict[str, object] + """The WAAP presents the user with a captcha""" + + handshake: Dict[str, object] + """The WAAP performs automatic browser validation""" + + monitor: Dict[str, object] + """The WAAP monitors the request but takes no action""" + + tag: ActionTag + """WAAP tag action gets a list of tags to tag the request scope with""" + + +class ConditionContentType(TypedDict, total=False): + """Match the requested Content-Type""" + + content_type: Required[SequenceNotStr[str]] + """The list of content types to match against""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionCountry(TypedDict, total=False): + """Match the country that the request originated from""" + + country_code: Required[SequenceNotStr[str]] + """ + A list of ISO 3166-1 alpha-2 formatted strings representing the countries to + match against + """ + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionFileExtension(TypedDict, total=False): + """Match the incoming file extension""" + + file_extension: Required[SequenceNotStr[str]] + """The list of file extensions to match against""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionHeader(TypedDict, total=False): + """Match an incoming request header""" + + header: Required[str] + """The request header name""" + + value: Required[str] + """The request header value""" + + match_type: Literal["Exact", "Contains"] + """The type of matching condition for header and value.""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionHeaderExists(TypedDict, total=False): + """Match when an incoming request header is present""" + + header: Required[str] + """The request header name""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionHTTPMethod(TypedDict, total=False): + """Match the incoming HTTP method""" + + http_method: Required[Literal["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]] + """HTTP methods of a request""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionIP(TypedDict, total=False): + """Match the incoming request against a single IP address""" + + ip_address: Required[str] + """A single IPv4 or IPv6 address""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionIPRange(TypedDict, total=False): + """Match the incoming request against an IP range""" + + lower_bound: Required[str] + """The lower bound IPv4 or IPv6 address to match against""" + + upper_bound: Required[str] + """The upper bound IPv4 or IPv6 address to match against""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionOrganization(TypedDict, total=False): + """ + Match the organization the request originated from, as determined by a WHOIS lookup of the requesting IP + """ + + organization: Required[str] + """The organization to match against""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionOwnerTypes(TypedDict, total=False): + """ + Match the type of organization that owns the IP address making an incoming request + """ + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + owner_types: List[ + Literal[ + "COMMERCIAL", + "EDUCATIONAL", + "GOVERNMENT", + "HOSTING_SERVICES", + "ISP", + "MOBILE_NETWORK", + "NETWORK", + "RESERVED", + ] + ] + """ + Match the type of organization that owns the IP address making an incoming + request + """ + + +class ConditionRequestRate(TypedDict, total=False): + """Match the rate at which requests come in that match certain conditions""" + + path_pattern: Required[str] + """A regular expression matching the URL path of the incoming request""" + + requests: Required[int] + """ + The number of incoming requests over the given time that can trigger a request + rate condition + """ + + time: Required[int] + """ + The number of seconds that the WAAP measures incoming requests over before + triggering a request rate condition + """ + + http_methods: List[Literal["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]] + """Possible HTTP request methods that can trigger a request rate condition""" + + ips: SequenceNotStr[str] + """A list of source IPs that can trigger a request rate condition""" + + user_defined_tag: str + """ + A user-defined tag that can be included in incoming requests and used to trigger + a request rate condition + """ + + +class ConditionResponseHeader(TypedDict, total=False): + """Match a response header""" + + header: Required[str] + """The response header name""" + + value: Required[str] + """The response header value""" + + match_type: Literal["Exact", "Contains"] + """The type of matching condition for header and value.""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionResponseHeaderExists(TypedDict, total=False): + """Match when a response header is present""" + + header: Required[str] + """The response header name""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionSessionRequestCount(TypedDict, total=False): + """Match the number of dynamic page requests made in a WAAP session""" + + request_count: Required[int] + """The number of dynamic requests in the session""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionTags(TypedDict, total=False): + """Matches requests based on specified tags""" + + tags: Required[SequenceNotStr[str]] + """A list of tags to match against the request tags""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionURL(TypedDict, total=False): + """Match the incoming request URL""" + + url: Required[str] + """ + The pattern to match against the request URL. Constraints depend on + `match_type`: + + - **Exact/Contains**: plain text matching (e.g., `/admin`, must comply with + `^[\\ww!\\$$~:#\\[[\\]]@\\((\\))*\\++,=\\//\\--\\..\\%%]+$`). + - **Regex**: a valid regular expression (e.g., `^/upload(/\\dd+)?/\\ww+`). + Lookahead/lookbehind constructs are forbidden. + """ + + match_type: Literal["Exact", "Contains", "Regex"] + """The type of matching condition.""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionUserAgent(TypedDict, total=False): + """Match the user agent making the request""" + + user_agent: Required[str] + """The user agent value to match""" + + match_type: Literal["Exact", "Contains"] + """The type of matching condition.""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionUserDefinedTags(TypedDict, total=False): + """Matches requests based on user-defined tags""" + + tags: Required[SequenceNotStr[str]] + """A list of user-defined tags to match against the request tags""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class Condition(TypedDict, total=False): + """ + The criteria of an incoming web request and the models of the various values those criteria can take + """ + + content_type: ConditionContentType + """Match the requested Content-Type""" + + country: ConditionCountry + """Match the country that the request originated from""" + + file_extension: ConditionFileExtension + """Match the incoming file extension""" + + header: ConditionHeader + """Match an incoming request header""" + + header_exists: ConditionHeaderExists + """Match when an incoming request header is present""" + + http_method: ConditionHTTPMethod + """Match the incoming HTTP method""" + + ip: ConditionIP + """Match the incoming request against a single IP address""" + + ip_range: ConditionIPRange + """Match the incoming request against an IP range""" + + organization: ConditionOrganization + """ + Match the organization the request originated from, as determined by a WHOIS + lookup of the requesting IP + """ + + owner_types: ConditionOwnerTypes + """ + Match the type of organization that owns the IP address making an incoming + request + """ + + request_rate: ConditionRequestRate + """Match the rate at which requests come in that match certain conditions""" + + response_header: ConditionResponseHeader + """Match a response header""" + + response_header_exists: ConditionResponseHeaderExists + """Match when a response header is present""" + + session_request_count: ConditionSessionRequestCount + """Match the number of dynamic page requests made in a WAAP session""" + + tags: ConditionTags + """Matches requests based on specified tags""" + + url: ConditionURL + """Match the incoming request URL""" + + user_agent: ConditionUserAgent + """Match the user agent making the request""" + + user_defined_tags: ConditionUserDefinedTags + """Matches requests based on user-defined tags""" diff --git a/src/gcore/types/waap/domains/custom_rule_delete_multiple_params.py b/src/gcore/types/waap/domains/custom_rule_delete_multiple_params.py new file mode 100644 index 00000000..2aabff0c --- /dev/null +++ b/src/gcore/types/waap/domains/custom_rule_delete_multiple_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["CustomRuleDeleteMultipleParams"] + + +class CustomRuleDeleteMultipleParams(TypedDict, total=False): + rule_ids: Required[Iterable[int]] + """The IDs of the rules to delete""" diff --git a/src/gcore/types/waap/domains/custom_rule_list_params.py b/src/gcore/types/waap/domains/custom_rule_list_params.py new file mode 100644 index 00000000..876668ca --- /dev/null +++ b/src/gcore/types/waap/domains/custom_rule_list_params.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["CustomRuleListParams"] + + +class CustomRuleListParams(TypedDict, total=False): + action: Literal["allow", "block", "captcha", "handshake", "monitor", "tag"] + """Filter to refine results by specific actions""" + + description: str + """Filter rules based on their description. Supports '\\**' as a wildcard character.""" + + enabled: bool + """Filter rules based on their active status""" + + limit: int + """Number of items to return""" + + name: str + """Filter rules based on their name. Supports '\\**' as a wildcard character.""" + + offset: int + """Number of items to skip""" + + ordering: Optional[ + Literal["id", "name", "description", "enabled", "action", "-id", "-name", "-description", "-enabled", "-action"] + ] + """Determine the field to order results by""" diff --git a/src/gcore/types/waap/domains/custom_rule_update_params.py b/src/gcore/types/waap/domains/custom_rule_update_params.py new file mode 100644 index 00000000..36c8e2c6 --- /dev/null +++ b/src/gcore/types/waap/domains/custom_rule_update_params.py @@ -0,0 +1,424 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = [ + "CustomRuleUpdateParams", + "Action", + "ActionBlock", + "ActionTag", + "Condition", + "ConditionContentType", + "ConditionCountry", + "ConditionFileExtension", + "ConditionHeader", + "ConditionHeaderExists", + "ConditionHTTPMethod", + "ConditionIP", + "ConditionIPRange", + "ConditionOrganization", + "ConditionOwnerTypes", + "ConditionRequestRate", + "ConditionResponseHeader", + "ConditionResponseHeaderExists", + "ConditionSessionRequestCount", + "ConditionTags", + "ConditionURL", + "ConditionUserAgent", + "ConditionUserDefinedTags", +] + + +class CustomRuleUpdateParams(TypedDict, total=False): + domain_id: Required[int] + """The domain ID""" + + action: Optional[Action] + """The action that a WAAP rule takes when triggered.""" + + conditions: Optional[Iterable[Condition]] + """The conditions required for the WAAP engine to trigger the rule. + + Rules may have between 1 and 5 conditions. All conditions must pass for the rule + to trigger + """ + + description: Optional[str] + """The description assigned to the rule""" + + enabled: Optional[bool] + """Whether or not the rule is enabled""" + + name: Optional[str] + """The name assigned to the rule""" + + +class ActionBlock(TypedDict, total=False): + """ + WAAP block action behavior could be configured with response status code and action duration. + """ + + action_duration: str + """How long a rule's block action will apply to subsequent requests. + + Can be specified in seconds or by using a numeral followed by 's', 'm', 'h', or + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. + """ + + status_code: Literal[403, 405, 418, 429] + """A custom HTTP status code that the WAAP returns if a rule blocks a request""" + + +class ActionTag(TypedDict, total=False): + """WAAP tag action gets a list of tags to tag the request scope with""" + + tags: Required[SequenceNotStr[str]] + """The list of user defined tags to tag the request with""" + + +class Action(TypedDict, total=False): + """The action that a WAAP rule takes when triggered.""" + + allow: Dict[str, object] + """The WAAP allows the request""" + + block: ActionBlock + """ + WAAP block action behavior could be configured with response status code and + action duration. + """ + + captcha: Dict[str, object] + """The WAAP presents the user with a captcha""" + + handshake: Dict[str, object] + """The WAAP performs automatic browser validation""" + + monitor: Dict[str, object] + """The WAAP monitors the request but takes no action""" + + tag: ActionTag + """WAAP tag action gets a list of tags to tag the request scope with""" + + +class ConditionContentType(TypedDict, total=False): + """Match the requested Content-Type""" + + content_type: Required[SequenceNotStr[str]] + """The list of content types to match against""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionCountry(TypedDict, total=False): + """Match the country that the request originated from""" + + country_code: Required[SequenceNotStr[str]] + """ + A list of ISO 3166-1 alpha-2 formatted strings representing the countries to + match against + """ + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionFileExtension(TypedDict, total=False): + """Match the incoming file extension""" + + file_extension: Required[SequenceNotStr[str]] + """The list of file extensions to match against""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionHeader(TypedDict, total=False): + """Match an incoming request header""" + + header: Required[str] + """The request header name""" + + value: Required[str] + """The request header value""" + + match_type: Literal["Exact", "Contains"] + """The type of matching condition for header and value.""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionHeaderExists(TypedDict, total=False): + """Match when an incoming request header is present""" + + header: Required[str] + """The request header name""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionHTTPMethod(TypedDict, total=False): + """Match the incoming HTTP method""" + + http_method: Required[Literal["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]] + """HTTP methods of a request""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionIP(TypedDict, total=False): + """Match the incoming request against a single IP address""" + + ip_address: Required[str] + """A single IPv4 or IPv6 address""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionIPRange(TypedDict, total=False): + """Match the incoming request against an IP range""" + + lower_bound: Required[str] + """The lower bound IPv4 or IPv6 address to match against""" + + upper_bound: Required[str] + """The upper bound IPv4 or IPv6 address to match against""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionOrganization(TypedDict, total=False): + """ + Match the organization the request originated from, as determined by a WHOIS lookup of the requesting IP + """ + + organization: Required[str] + """The organization to match against""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionOwnerTypes(TypedDict, total=False): + """ + Match the type of organization that owns the IP address making an incoming request + """ + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + owner_types: List[ + Literal[ + "COMMERCIAL", + "EDUCATIONAL", + "GOVERNMENT", + "HOSTING_SERVICES", + "ISP", + "MOBILE_NETWORK", + "NETWORK", + "RESERVED", + ] + ] + """ + Match the type of organization that owns the IP address making an incoming + request + """ + + +class ConditionRequestRate(TypedDict, total=False): + """Match the rate at which requests come in that match certain conditions""" + + path_pattern: Required[str] + """A regular expression matching the URL path of the incoming request""" + + requests: Required[int] + """ + The number of incoming requests over the given time that can trigger a request + rate condition + """ + + time: Required[int] + """ + The number of seconds that the WAAP measures incoming requests over before + triggering a request rate condition + """ + + http_methods: List[Literal["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]] + """Possible HTTP request methods that can trigger a request rate condition""" + + ips: SequenceNotStr[str] + """A list of source IPs that can trigger a request rate condition""" + + user_defined_tag: str + """ + A user-defined tag that can be included in incoming requests and used to trigger + a request rate condition + """ + + +class ConditionResponseHeader(TypedDict, total=False): + """Match a response header""" + + header: Required[str] + """The response header name""" + + value: Required[str] + """The response header value""" + + match_type: Literal["Exact", "Contains"] + """The type of matching condition for header and value.""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionResponseHeaderExists(TypedDict, total=False): + """Match when a response header is present""" + + header: Required[str] + """The response header name""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionSessionRequestCount(TypedDict, total=False): + """Match the number of dynamic page requests made in a WAAP session""" + + request_count: Required[int] + """The number of dynamic requests in the session""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionTags(TypedDict, total=False): + """Matches requests based on specified tags""" + + tags: Required[SequenceNotStr[str]] + """A list of tags to match against the request tags""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionURL(TypedDict, total=False): + """Match the incoming request URL""" + + url: Required[str] + """ + The pattern to match against the request URL. Constraints depend on + `match_type`: + + - **Exact/Contains**: plain text matching (e.g., `/admin`, must comply with + `^[\\ww!\\$$~:#\\[[\\]]@\\((\\))*\\++,=\\//\\--\\..\\%%]+$`). + - **Regex**: a valid regular expression (e.g., `^/upload(/\\dd+)?/\\ww+`). + Lookahead/lookbehind constructs are forbidden. + """ + + match_type: Literal["Exact", "Contains", "Regex"] + """The type of matching condition.""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionUserAgent(TypedDict, total=False): + """Match the user agent making the request""" + + user_agent: Required[str] + """The user agent value to match""" + + match_type: Literal["Exact", "Contains"] + """The type of matching condition.""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionUserDefinedTags(TypedDict, total=False): + """Matches requests based on user-defined tags""" + + tags: Required[SequenceNotStr[str]] + """A list of user-defined tags to match against the request tags""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class Condition(TypedDict, total=False): + """ + The criteria of an incoming web request and the models of the various values those criteria can take + """ + + content_type: ConditionContentType + """Match the requested Content-Type""" + + country: ConditionCountry + """Match the country that the request originated from""" + + file_extension: ConditionFileExtension + """Match the incoming file extension""" + + header: ConditionHeader + """Match an incoming request header""" + + header_exists: ConditionHeaderExists + """Match when an incoming request header is present""" + + http_method: ConditionHTTPMethod + """Match the incoming HTTP method""" + + ip: ConditionIP + """Match the incoming request against a single IP address""" + + ip_range: ConditionIPRange + """Match the incoming request against an IP range""" + + organization: ConditionOrganization + """ + Match the organization the request originated from, as determined by a WHOIS + lookup of the requesting IP + """ + + owner_types: ConditionOwnerTypes + """ + Match the type of organization that owns the IP address making an incoming + request + """ + + request_rate: ConditionRequestRate + """Match the rate at which requests come in that match certain conditions""" + + response_header: ConditionResponseHeader + """Match a response header""" + + response_header_exists: ConditionResponseHeaderExists + """Match when a response header is present""" + + session_request_count: ConditionSessionRequestCount + """Match the number of dynamic page requests made in a WAAP session""" + + tags: ConditionTags + """Matches requests based on specified tags""" + + url: ConditionURL + """Match the incoming request URL""" + + user_agent: ConditionUserAgent + """Match the user agent making the request""" + + user_defined_tags: ConditionUserDefinedTags + """Matches requests based on user-defined tags""" diff --git a/src/gcore/types/waap/domains/firewall_rule_create_params.py b/src/gcore/types/waap/domains/firewall_rule_create_params.py new file mode 100644 index 00000000..73e76cdc --- /dev/null +++ b/src/gcore/types/waap/domains/firewall_rule_create_params.py @@ -0,0 +1,90 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["FirewallRuleCreateParams", "Action", "ActionBlock", "Condition", "ConditionIP", "ConditionIPRange"] + + +class FirewallRuleCreateParams(TypedDict, total=False): + action: Required[Action] + """The action that the rule takes when triggered""" + + conditions: Required[Iterable[Condition]] + """The condition required for the WAAP engine to trigger the rule.""" + + enabled: Required[bool] + """Whether or not the rule is enabled""" + + name: Required[str] + """The name assigned to the rule""" + + description: str + """The description assigned to the rule""" + + +class ActionBlock(TypedDict, total=False): + """ + WAAP block action behavior could be configured with response status code and action duration. + """ + + action_duration: str + """How long a rule's block action will apply to subsequent requests. + + Can be specified in seconds or by using a numeral followed by 's', 'm', 'h', or + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. + """ + + status_code: Literal[403, 405, 418, 429] + """A custom HTTP status code that the WAAP returns if a rule blocks a request""" + + +class Action(TypedDict, total=False): + """The action that the rule takes when triggered""" + + allow: Optional[Dict[str, object]] + """The WAAP allows the request""" + + block: Optional[ActionBlock] + """ + WAAP block action behavior could be configured with response status code and + action duration. + """ + + +class ConditionIP(TypedDict, total=False): + """Match the incoming request against a single IP address""" + + ip_address: Required[str] + """A single IPv4 or IPv6 address""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionIPRange(TypedDict, total=False): + """Match the incoming request against an IP range""" + + lower_bound: Required[str] + """The lower bound IPv4 or IPv6 address to match against""" + + upper_bound: Required[str] + """The upper bound IPv4 or IPv6 address to match against""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class Condition(TypedDict, total=False): + """ + The criteria of an incoming web request and the models of the various values those criteria can take + """ + + ip: ConditionIP + """Match the incoming request against a single IP address""" + + ip_range: ConditionIPRange + """Match the incoming request against an IP range""" diff --git a/src/gcore/types/waap/domains/firewall_rule_delete_multiple_params.py b/src/gcore/types/waap/domains/firewall_rule_delete_multiple_params.py new file mode 100644 index 00000000..5228c20a --- /dev/null +++ b/src/gcore/types/waap/domains/firewall_rule_delete_multiple_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["FirewallRuleDeleteMultipleParams"] + + +class FirewallRuleDeleteMultipleParams(TypedDict, total=False): + rule_ids: Required[Iterable[int]] + """The IDs of the rules to delete""" diff --git a/src/gcore/types/waap/domains/firewall_rule_list_params.py b/src/gcore/types/waap/domains/firewall_rule_list_params.py new file mode 100644 index 00000000..29563ec2 --- /dev/null +++ b/src/gcore/types/waap/domains/firewall_rule_list_params.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["FirewallRuleListParams"] + + +class FirewallRuleListParams(TypedDict, total=False): + action: Literal["allow", "block"] + """Filter to refine results by specific firewall actions""" + + description: str + """Filter rules based on their description. Supports '\\**' as a wildcard character.""" + + enabled: bool + """Filter rules based on their active status""" + + limit: int + """Number of items to return""" + + name: str + """Filter rules based on their name. Supports '\\**' as a wildcard character.""" + + offset: int + """Number of items to skip""" + + ordering: Optional[ + Literal["id", "name", "description", "enabled", "action", "-id", "-name", "-description", "-enabled", "-action"] + ] + """Determine the field to order results by""" diff --git a/src/gcore/types/waap/domains/firewall_rule_update_params.py b/src/gcore/types/waap/domains/firewall_rule_update_params.py new file mode 100644 index 00000000..e6378ef6 --- /dev/null +++ b/src/gcore/types/waap/domains/firewall_rule_update_params.py @@ -0,0 +1,93 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["FirewallRuleUpdateParams", "Action", "ActionBlock", "Condition", "ConditionIP", "ConditionIPRange"] + + +class FirewallRuleUpdateParams(TypedDict, total=False): + domain_id: Required[int] + """The domain ID""" + + action: Optional[Action] + """The action that a firewall rule takes when triggered""" + + conditions: Optional[Iterable[Condition]] + """The condition required for the WAAP engine to trigger the rule.""" + + description: Optional[str] + """The description assigned to the rule""" + + enabled: Optional[bool] + """Whether or not the rule is enabled""" + + name: Optional[str] + """The name assigned to the rule""" + + +class ActionBlock(TypedDict, total=False): + """ + WAAP block action behavior could be configured with response status code and action duration. + """ + + action_duration: str + """How long a rule's block action will apply to subsequent requests. + + Can be specified in seconds or by using a numeral followed by 's', 'm', 'h', or + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. + """ + + status_code: Literal[403, 405, 418, 429] + """A custom HTTP status code that the WAAP returns if a rule blocks a request""" + + +class Action(TypedDict, total=False): + """The action that a firewall rule takes when triggered""" + + allow: Optional[Dict[str, object]] + """The WAAP allows the request""" + + block: Optional[ActionBlock] + """ + WAAP block action behavior could be configured with response status code and + action duration. + """ + + +class ConditionIP(TypedDict, total=False): + """Match the incoming request against a single IP address""" + + ip_address: Required[str] + """A single IPv4 or IPv6 address""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionIPRange(TypedDict, total=False): + """Match the incoming request against an IP range""" + + lower_bound: Required[str] + """The lower bound IPv4 or IPv6 address to match against""" + + upper_bound: Required[str] + """The upper bound IPv4 or IPv6 address to match against""" + + negation: bool + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class Condition(TypedDict, total=False): + """ + The criteria of an incoming web request and the models of the various values those criteria can take + """ + + ip: ConditionIP + """Match the incoming request against a single IP address""" + + ip_range: ConditionIPRange + """Match the incoming request against an IP range""" diff --git a/src/gcore/types/waap/domains/insight_list_params.py b/src/gcore/types/waap/domains/insight_list_params.py new file mode 100644 index 00000000..7163f181 --- /dev/null +++ b/src/gcore/types/waap/domains/insight_list_params.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["InsightListParams"] + + +class InsightListParams(TypedDict, total=False): + id: Optional[SequenceNotStr[str]] + """The ID of the insight""" + + description: Optional[str] + """The description of the insight. Supports '\\**' as a wildcard.""" + + insight_type: Optional[SequenceNotStr[str]] + """The type of the insight""" + + limit: int + """Number of items to return""" + + offset: int + """Number of items to skip""" + + ordering: Literal[ + "id", + "-id", + "insight_type", + "-insight_type", + "first_seen", + "-first_seen", + "last_seen", + "-last_seen", + "last_status_change", + "-last_status_change", + "status", + "-status", + ] + """Sort the response by given field.""" + + status: Optional[List[Literal["OPEN", "ACKED", "CLOSED"]]] + """The status of the insight""" diff --git a/src/gcore/types/waap/domains/insight_replace_params.py b/src/gcore/types/waap/domains/insight_replace_params.py new file mode 100644 index 00000000..46dc81b4 --- /dev/null +++ b/src/gcore/types/waap/domains/insight_replace_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["InsightReplaceParams"] + + +class InsightReplaceParams(TypedDict, total=False): + domain_id: Required[int] + """The domain ID""" + + status: Required[Literal["OPEN", "ACKED", "CLOSED"]] + """The status of the insight""" diff --git a/src/gcore/types/waap/domains/insight_silence_create_params.py b/src/gcore/types/waap/domains/insight_silence_create_params.py new file mode 100644 index 00000000..d4376cd1 --- /dev/null +++ b/src/gcore/types/waap/domains/insight_silence_create_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union +from datetime import datetime +from typing_extensions import Required, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["InsightSilenceCreateParams"] + + +class InsightSilenceCreateParams(TypedDict, total=False): + author: Required[str] + """The author of the silence""" + + comment: Required[str] + """A comment explaining the reason for the silence""" + + insight_type: Required[str] + """The slug of the insight type""" + + labels: Required[Dict[str, str]] + """A hash table of label names and values that apply to the insight silence""" + + expire_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The date and time the silence expires in ISO 8601 format""" diff --git a/src/gcore/types/waap/domains/insight_silence_list_params.py b/src/gcore/types/waap/domains/insight_silence_list_params.py new file mode 100644 index 00000000..affcad4d --- /dev/null +++ b/src/gcore/types/waap/domains/insight_silence_list_params.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["InsightSilenceListParams"] + + +class InsightSilenceListParams(TypedDict, total=False): + id: Optional[SequenceNotStr[str]] + """The ID of the insight silence""" + + author: Optional[str] + """The author of the insight silence""" + + comment: Optional[str] + """The comment of the insight silence""" + + insight_type: Optional[SequenceNotStr[str]] + """The type of the insight silence""" + + limit: int + """Number of items to return""" + + offset: int + """Number of items to skip""" + + ordering: Literal[ + "id", + "-id", + "insight_type", + "-insight_type", + "comment", + "-comment", + "author", + "-author", + "expire_at", + "-expire_at", + ] + """Sort the response by given field.""" diff --git a/src/gcore/types/waap/domains/insight_silence_update_params.py b/src/gcore/types/waap/domains/insight_silence_update_params.py new file mode 100644 index 00000000..23b4c0a7 --- /dev/null +++ b/src/gcore/types/waap/domains/insight_silence_update_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union +from datetime import datetime +from typing_extensions import Required, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["InsightSilenceUpdateParams"] + + +class InsightSilenceUpdateParams(TypedDict, total=False): + domain_id: Required[int] + """The domain ID""" + + author: Required[str] + """The author of the silence""" + + comment: Required[str] + """A comment explaining the reason for the silence""" + + expire_at: Required[Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")]] + """The date and time the silence expires in ISO 8601 format""" + + labels: Dict[str, str] + """A hash table of label names and values that apply to the insight silence""" diff --git a/src/gcore/types/waap/domains/setting_update_params.py b/src/gcore/types/waap/domains/setting_update_params.py new file mode 100644 index 00000000..8a7f804b --- /dev/null +++ b/src/gcore/types/waap/domains/setting_update_params.py @@ -0,0 +1,53 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["SettingUpdateParams", "API", "DDOS"] + + +class SettingUpdateParams(TypedDict, total=False): + api: API + """Editable API settings of a domain""" + + ddos: DDOS + """Editable DDoS settings for a domain.""" + + +class API(TypedDict, total=False): + """Editable API settings of a domain""" + + api_urls: SequenceNotStr[str] + """The API URLs for a domain. + + If your domain has a common base URL for all API paths, it can be set here + """ + + is_api: bool + """Indicates if the domain is an API domain. + + All requests to an API domain are treated as API requests. If this is set to + true then the `api_urls` field is ignored. + """ + + +class DDOS(TypedDict, total=False): + """Editable DDoS settings for a domain.""" + + burst_threshold: int + """The burst threshold detects sudden rises in traffic. + + If it is met and the number of requests is at least five times the last 2-second + interval, DDoS protection will activate. Default is 1000. + """ + + global_threshold: int + """ + The global threshold is responsible for identifying DDoS attacks with a slow + rise in traffic. If the threshold is met and the current number of requests is + at least double that of the previous 10-second window, DDoS protection will + activate. Default is 5000. + """ diff --git a/src/gcore/types/waap/domains/statistic_get_ddos_attacks_params.py b/src/gcore/types/waap/domains/statistic_get_ddos_attacks_params.py new file mode 100644 index 00000000..d56610af --- /dev/null +++ b/src/gcore/types/waap/domains/statistic_get_ddos_attacks_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Literal, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["StatisticGetDDOSAttacksParams"] + + +class StatisticGetDDOSAttacksParams(TypedDict, total=False): + end_time: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """Filter attacks up to a specified end date in ISO 8601 format""" + + limit: int + """Number of items to return""" + + offset: int + """Number of items to skip""" + + ordering: Literal["start_time", "-start_time", "end_time", "-end_time"] + """Sort the response by given field.""" + + start_time: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """Filter attacks starting from a specified date in ISO 8601 format""" diff --git a/src/gcore/types/waap/domains/statistic_get_ddos_info_params.py b/src/gcore/types/waap/domains/statistic_get_ddos_info_params.py new file mode 100644 index 00000000..3b8406b8 --- /dev/null +++ b/src/gcore/types/waap/domains/statistic_get_ddos_info_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["StatisticGetDDOSInfoParams"] + + +class StatisticGetDDOSInfoParams(TypedDict, total=False): + group_by: Required[Literal["URL", "User-Agent", "IP"]] + """The identity of the requests to group by""" + + start: Required[str] + """Filter data items starting from a specified date in ISO 8601 format""" + + end: Optional[str] + """Filter data items up to a specified end date in ISO 8601 format. + + If not provided, defaults to the current date and time. + """ + + limit: int + """Number of items to return""" + + offset: int + """Number of items to skip""" diff --git a/src/gcore/types/waap/domains/statistic_get_events_aggregated_params.py b/src/gcore/types/waap/domains/statistic_get_events_aggregated_params.py new file mode 100644 index 00000000..4cfc9bcd --- /dev/null +++ b/src/gcore/types/waap/domains/statistic_get_events_aggregated_params.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["StatisticGetEventsAggregatedParams"] + + +class StatisticGetEventsAggregatedParams(TypedDict, total=False): + start: Required[str] + """Filter data items starting from a specified date in ISO 8601 format""" + + action: Optional[List[Literal["allow", "block", "captcha", "handshake"]]] + """A list of action names to filter on.""" + + end: Optional[str] + """Filter data items up to a specified end date in ISO 8601 format. + + If not provided, defaults to the current date and time. + """ + + ip: Optional[SequenceNotStr[str]] + """A list of IPs to filter event statistics.""" + + reference_id: Optional[SequenceNotStr[str]] + """A list of reference IDs to filter event statistics.""" + + result: Optional[List[Literal["passed", "blocked", "monitored", "allowed"]]] + """A list of results to filter event statistics.""" diff --git a/src/gcore/types/waap/domains/statistic_get_requests_series_params.py b/src/gcore/types/waap/domains/statistic_get_requests_series_params.py new file mode 100644 index 00000000..ef36b532 --- /dev/null +++ b/src/gcore/types/waap/domains/statistic_get_requests_series_params.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal, Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["StatisticGetRequestsSeriesParams"] + + +class StatisticGetRequestsSeriesParams(TypedDict, total=False): + start: Required[str] + """Filter data items starting from a specified date in ISO 8601 format""" + + actions: List[Literal["allow", "block", "captcha", "handshake"]] + """Filter the response by actions.""" + + countries: SequenceNotStr[str] + """Filter the response by country codes in ISO 3166-1 alpha-2 format.""" + + end: Optional[str] + """Filter data items up to a specified end date in ISO 8601 format. + + If not provided, defaults to the current date and time. + """ + + ip: str + """Filter the response by IP.""" + + limit: int + """Number of items to return""" + + offset: int + """Number of items to skip""" + + ordering: str + """Sort the response by given field.""" + + reference_id: str + """Filter the response by reference ID.""" + + security_rule_name: str + """Filter the response by security rule name.""" + + status_code: int + """Filter the response by response code.""" + + traffic_types: List[ + Literal[ + "policy_allowed", + "policy_blocked", + "custom_rule_allowed", + "custom_blocked", + "legit_requests", + "sanctioned", + "dynamic", + "api", + "static", + "ajax", + "redirects", + "monitor", + "err_40x", + "err_50x", + "passed_to_origin", + "timeout", + "other", + "ddos", + "legit", + "monitored", + ] + ] + """Filter the response by traffic types.""" diff --git a/src/gcore/types/waap/domains/statistic_get_traffic_series_params.py b/src/gcore/types/waap/domains/statistic_get_traffic_series_params.py new file mode 100644 index 00000000..18b815fb --- /dev/null +++ b/src/gcore/types/waap/domains/statistic_get_traffic_series_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["StatisticGetTrafficSeriesParams"] + + +class StatisticGetTrafficSeriesParams(TypedDict, total=False): + resolution: Required[Literal["daily", "hourly", "minutely"]] + """Specifies the granularity of the result data.""" + + start: Required[str] + """Filter data items starting from a specified date in ISO 8601 format""" + + end: Optional[str] + """Filter data items up to a specified end date in ISO 8601 format. + + If not provided, defaults to the current date and time. + """ diff --git a/src/gcore/types/waap/domains/statistic_get_traffic_series_response.py b/src/gcore/types/waap/domains/statistic_get_traffic_series_response.py new file mode 100644 index 00000000..2be7468d --- /dev/null +++ b/src/gcore/types/waap/domains/statistic_get_traffic_series_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .waap_traffic_metrics import WaapTrafficMetrics + +__all__ = ["StatisticGetTrafficSeriesResponse"] + +StatisticGetTrafficSeriesResponse: TypeAlias = List[WaapTrafficMetrics] diff --git a/src/gcore/types/waap/domains/waap_advanced_rule.py b/src/gcore/types/waap/domains/waap_advanced_rule.py new file mode 100644 index 00000000..c0f735e1 --- /dev/null +++ b/src/gcore/types/waap/domains/waap_advanced_rule.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["WaapAdvancedRule", "Action", "ActionBlock", "ActionTag"] + + +class ActionBlock(BaseModel): + """ + WAAP block action behavior could be configured with response status code and action duration. + """ + + action_duration: Optional[str] = None + """How long a rule's block action will apply to subsequent requests. + + Can be specified in seconds or by using a numeral followed by 's', 'm', 'h', or + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. + """ + + status_code: Optional[Literal[403, 405, 418, 429]] = None + """A custom HTTP status code that the WAAP returns if a rule blocks a request""" + + +class ActionTag(BaseModel): + """WAAP tag action gets a list of tags to tag the request scope with""" + + tags: List[str] + """The list of user defined tags to tag the request with""" + + +class Action(BaseModel): + """The action that the rule takes when triggered. + + Only one action can be set per rule. + """ + + allow: Optional[Dict[str, object]] = None + """The WAAP allows the request""" + + block: Optional[ActionBlock] = None + """ + WAAP block action behavior could be configured with response status code and + action duration. + """ + + captcha: Optional[Dict[str, object]] = None + """The WAAP presents the user with a captcha""" + + handshake: Optional[Dict[str, object]] = None + """The WAAP performs automatic browser validation""" + + monitor: Optional[Dict[str, object]] = None + """The WAAP monitors the request but takes no action""" + + tag: Optional[ActionTag] = None + """WAAP tag action gets a list of tags to tag the request scope with""" + + +class WaapAdvancedRule(BaseModel): + """An advanced WAAP rule applied to a domain""" + + id: int + """The unique identifier for the rule""" + + action: Action + """The action that the rule takes when triggered. + + Only one action can be set per rule. + """ + + enabled: bool + """Whether or not the rule is enabled""" + + name: str + """The name assigned to the rule""" + + source: str + """A CEL syntax expression that contains the rule's conditions. + + Allowed objects are: request, whois, session, response, tags, + `user_defined_tags`, `user_agent`, `client_data`. + + More info can be found here: + https://gcore.com/docs/waap/waap-rules/advanced-rules + """ + + description: Optional[str] = None + """The description assigned to the rule""" + + phase: Optional[Literal["access", "header_filter", "body_filter"]] = None + """The WAAP request/response phase for applying the rule. Default is "access". + + The "access" phase is responsible for modifying the request before it is sent to + the origin server. + + The "header_filter" phase is responsible for modifying the HTTP headers of a + response before they are sent back to the client. + + The "body_filter" phase is responsible for modifying the body of a response + before it is sent back to the client. + """ diff --git a/src/gcore/types/waap/domains/waap_api_discovery_settings.py b/src/gcore/types/waap/domains/waap_api_discovery_settings.py new file mode 100644 index 00000000..3b6339d8 --- /dev/null +++ b/src/gcore/types/waap/domains/waap_api_discovery_settings.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel + +__all__ = ["WaapAPIDiscoverySettings"] + + +class WaapAPIDiscoverySettings(BaseModel): + """Response model for the API discovery settings""" + + description_file_location: Optional[str] = FieldInfo(alias="descriptionFileLocation", default=None) + """The URL of the API description file. + + This will be periodically scanned if `descriptionFileScanEnabled` is enabled. + Supported formats are YAML and JSON, and it must adhere to OpenAPI versions 2, + 3, or 3.1. + """ + + description_file_scan_enabled: Optional[bool] = FieldInfo(alias="descriptionFileScanEnabled", default=None) + """Indicates if periodic scan of the description file is enabled""" + + description_file_scan_interval_hours: Optional[int] = FieldInfo( + alias="descriptionFileScanIntervalHours", default=None + ) + """The interval in hours for scanning the description file""" + + traffic_scan_enabled: Optional[bool] = FieldInfo(alias="trafficScanEnabled", default=None) + """Indicates if traffic scan is enabled. + + Traffic scan is used to discover undocumented APIs + """ + + traffic_scan_interval_hours: Optional[int] = FieldInfo(alias="trafficScanIntervalHours", default=None) + """The interval in hours for scanning the traffic""" diff --git a/src/gcore/types/waap/domains/waap_api_path.py b/src/gcore/types/waap/domains/waap_api_path.py new file mode 100644 index 00000000..ad57e1c2 --- /dev/null +++ b/src/gcore/types/waap/domains/waap_api_path.py @@ -0,0 +1,52 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["WaapAPIPath"] + + +class WaapAPIPath(BaseModel): + """Response model for the API path""" + + id: str + """The path ID""" + + api_groups: List[str] + """An array of api groups associated with the API path""" + + api_version: str + """The API version""" + + first_detected: datetime + """The date and time in ISO 8601 format the API path was first detected.""" + + http_scheme: Literal["HTTP", "HTTPS"] + """The HTTP version of the API path""" + + last_detected: datetime + """The date and time in ISO 8601 format the API path was last detected.""" + + method: Literal["GET", "POST", "PUT", "PATCH", "DELETE", "TRACE", "HEAD", "OPTIONS"] + """The API RESTful method""" + + path: str + """ + The API path, locations that are saved for resource IDs will be put in curly + brackets + """ + + request_count: int + """The number of requests for this path in the last 24 hours""" + + source: Literal["API_DESCRIPTION_FILE", "TRAFFIC_SCAN", "USER_DEFINED"] + """The source of the discovered API""" + + status: Literal["CONFIRMED_API", "POTENTIAL_API", "NOT_API", "DELISTED_API"] + """The status of the discovered API path""" + + tags: List[str] + """An array of tags associated with the API path""" diff --git a/src/gcore/types/waap/domains/waap_api_scan_result.py b/src/gcore/types/waap/domains/waap_api_scan_result.py new file mode 100644 index 00000000..c2bb18fa --- /dev/null +++ b/src/gcore/types/waap/domains/waap_api_scan_result.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["WaapAPIScanResult"] + + +class WaapAPIScanResult(BaseModel): + """The result of a scan""" + + id: str + """The scan ID""" + + end_time: Optional[datetime] = None + """The date and time the scan ended""" + + message: str + """The message associated with the scan""" + + start_time: datetime + """The date and time the scan started""" + + status: Literal["SUCCESS", "FAILURE", "IN_PROGRESS"] + """The status of the scan""" + + type: Literal["TRAFFIC_SCAN", "API_DESCRIPTION_FILE_SCAN"] + """The type of scan""" diff --git a/src/gcore/types/waap/domains/waap_blocked_statistics.py b/src/gcore/types/waap/domains/waap_blocked_statistics.py new file mode 100644 index 00000000..43aacc6b --- /dev/null +++ b/src/gcore/types/waap/domains/waap_blocked_statistics.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union + +from ...._models import BaseModel + +__all__ = ["WaapBlockedStatistics"] + + +class WaapBlockedStatistics(BaseModel): + """A collection of total numbers of events with blocked results per criteria""" + + action: List[List[Union[str, int]]] + """A collection of event counts per action. + + The first item is the action's abbreviation/full action name, and the second + item is the number of events + """ + + country: List[List[Union[str, int]]] + """A collection of event counts per country of origin. + + The first item is the country's ISO 3166-1 alpha-2, and the second item is the + number of events + """ + + org: List[List[Union[str, int]]] + """A collection of event counts per organization that owns the event's client IP. + + The first item is the organization's name, and the second item is the number of + events + """ + + rule_name: List[List[Union[str, int]]] + """A collection of event counts per rule that triggered the event. + + The first item is the rule's name, and the second item is the number of events + """ diff --git a/src/gcore/types/waap/domains/waap_count_statistics.py b/src/gcore/types/waap/domains/waap_count_statistics.py new file mode 100644 index 00000000..daa586f0 --- /dev/null +++ b/src/gcore/types/waap/domains/waap_count_statistics.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union + +from ...._models import BaseModel + +__all__ = ["WaapCountStatistics"] + + +class WaapCountStatistics(BaseModel): + """A collection of total numbers of events per criteria""" + + action: List[List[Union[str, int]]] + """A collection of event counts per action. + + The first item is the action's abbreviation/full action name, and the second + item is the number of events + """ + + country: List[List[Union[str, int]]] + """A collection of event counts per country of origin. + + The first item is the country's ISO 3166-1 alpha-2, and the second item is the + number of events + """ + + org: List[List[Union[str, int]]] + """A collection of event counts per organization that owns the event's client IP. + + The first item is the organization's name, and the second item is the number of + events + """ + + rule_name: List[List[Union[str, int]]] + """A collection of event counts per rule that triggered the event. + + The first item is the rule's name, and the second item is the number of events + """ diff --git a/src/gcore/types/waap/domains/waap_custom_rule.py b/src/gcore/types/waap/domains/waap_custom_rule.py new file mode 100644 index 00000000..db35a837 --- /dev/null +++ b/src/gcore/types/waap/domains/waap_custom_rule.py @@ -0,0 +1,434 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = [ + "WaapCustomRule", + "Action", + "ActionBlock", + "ActionTag", + "Condition", + "ConditionContentType", + "ConditionCountry", + "ConditionFileExtension", + "ConditionHeader", + "ConditionHeaderExists", + "ConditionHTTPMethod", + "ConditionIP", + "ConditionIPRange", + "ConditionOrganization", + "ConditionOwnerTypes", + "ConditionRequestRate", + "ConditionResponseHeader", + "ConditionResponseHeaderExists", + "ConditionSessionRequestCount", + "ConditionTags", + "ConditionURL", + "ConditionUserAgent", + "ConditionUserDefinedTags", +] + + +class ActionBlock(BaseModel): + """ + WAAP block action behavior could be configured with response status code and action duration. + """ + + action_duration: Optional[str] = None + """How long a rule's block action will apply to subsequent requests. + + Can be specified in seconds or by using a numeral followed by 's', 'm', 'h', or + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. + """ + + status_code: Optional[Literal[403, 405, 418, 429]] = None + """A custom HTTP status code that the WAAP returns if a rule blocks a request""" + + +class ActionTag(BaseModel): + """WAAP tag action gets a list of tags to tag the request scope with""" + + tags: List[str] + """The list of user defined tags to tag the request with""" + + +class Action(BaseModel): + """The action that the rule takes when triggered. + + Only one action can be set per rule. + """ + + allow: Optional[Dict[str, object]] = None + """The WAAP allows the request""" + + block: Optional[ActionBlock] = None + """ + WAAP block action behavior could be configured with response status code and + action duration. + """ + + captcha: Optional[Dict[str, object]] = None + """The WAAP presents the user with a captcha""" + + handshake: Optional[Dict[str, object]] = None + """The WAAP performs automatic browser validation""" + + monitor: Optional[Dict[str, object]] = None + """The WAAP monitors the request but takes no action""" + + tag: Optional[ActionTag] = None + """WAAP tag action gets a list of tags to tag the request scope with""" + + +class ConditionContentType(BaseModel): + """Match the requested Content-Type""" + + content_type: List[str] + """The list of content types to match against""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionCountry(BaseModel): + """Match the country that the request originated from""" + + country_code: List[str] + """ + A list of ISO 3166-1 alpha-2 formatted strings representing the countries to + match against + """ + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionFileExtension(BaseModel): + """Match the incoming file extension""" + + file_extension: List[str] + """The list of file extensions to match against""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionHeader(BaseModel): + """Match an incoming request header""" + + header: str + """The request header name""" + + value: str + """The request header value""" + + match_type: Optional[Literal["Exact", "Contains"]] = None + """The type of matching condition for header and value.""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionHeaderExists(BaseModel): + """Match when an incoming request header is present""" + + header: str + """The request header name""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionHTTPMethod(BaseModel): + """Match the incoming HTTP method""" + + http_method: Literal["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"] + """HTTP methods of a request""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionIP(BaseModel): + """Match the incoming request against a single IP address""" + + ip_address: str + """A single IPv4 or IPv6 address""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionIPRange(BaseModel): + """Match the incoming request against an IP range""" + + lower_bound: str + """The lower bound IPv4 or IPv6 address to match against""" + + upper_bound: str + """The upper bound IPv4 or IPv6 address to match against""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionOrganization(BaseModel): + """ + Match the organization the request originated from, as determined by a WHOIS lookup of the requesting IP + """ + + organization: str + """The organization to match against""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionOwnerTypes(BaseModel): + """ + Match the type of organization that owns the IP address making an incoming request + """ + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + owner_types: Optional[ + List[ + Literal[ + "COMMERCIAL", + "EDUCATIONAL", + "GOVERNMENT", + "HOSTING_SERVICES", + "ISP", + "MOBILE_NETWORK", + "NETWORK", + "RESERVED", + ] + ] + ] = None + """ + Match the type of organization that owns the IP address making an incoming + request + """ + + +class ConditionRequestRate(BaseModel): + """Match the rate at which requests come in that match certain conditions""" + + path_pattern: str + """A regular expression matching the URL path of the incoming request""" + + requests: int + """ + The number of incoming requests over the given time that can trigger a request + rate condition + """ + + time: int + """ + The number of seconds that the WAAP measures incoming requests over before + triggering a request rate condition + """ + + http_methods: Optional[ + List[Literal["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]] + ] = None + """Possible HTTP request methods that can trigger a request rate condition""" + + ips: Optional[List[str]] = None + """A list of source IPs that can trigger a request rate condition""" + + user_defined_tag: Optional[str] = None + """ + A user-defined tag that can be included in incoming requests and used to trigger + a request rate condition + """ + + +class ConditionResponseHeader(BaseModel): + """Match a response header""" + + header: str + """The response header name""" + + value: str + """The response header value""" + + match_type: Optional[Literal["Exact", "Contains"]] = None + """The type of matching condition for header and value.""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionResponseHeaderExists(BaseModel): + """Match when a response header is present""" + + header: str + """The response header name""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionSessionRequestCount(BaseModel): + """Match the number of dynamic page requests made in a WAAP session""" + + request_count: int + """The number of dynamic requests in the session""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionTags(BaseModel): + """Matches requests based on specified tags""" + + tags: List[str] + """A list of tags to match against the request tags""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionURL(BaseModel): + """Match the incoming request URL""" + + url: str + """ + The pattern to match against the request URL. Constraints depend on + `match_type`: + + - **Exact/Contains**: plain text matching (e.g., `/admin`, must comply with + `^[\\ww!\\$$~:#\\[[\\]]@\\((\\))*\\++,=\\//\\--\\..\\%%]+$`). + - **Regex**: a valid regular expression (e.g., `^/upload(/\\dd+)?/\\ww+`). + Lookahead/lookbehind constructs are forbidden. + """ + + match_type: Optional[Literal["Exact", "Contains", "Regex"]] = None + """The type of matching condition.""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionUserAgent(BaseModel): + """Match the user agent making the request""" + + user_agent: str + """The user agent value to match""" + + match_type: Optional[Literal["Exact", "Contains"]] = None + """The type of matching condition.""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionUserDefinedTags(BaseModel): + """Matches requests based on user-defined tags""" + + tags: List[str] + """A list of user-defined tags to match against the request tags""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class Condition(BaseModel): + """ + The criteria of an incoming web request and the models of the various values those criteria can take + """ + + content_type: Optional[ConditionContentType] = None + """Match the requested Content-Type""" + + country: Optional[ConditionCountry] = None + """Match the country that the request originated from""" + + file_extension: Optional[ConditionFileExtension] = None + """Match the incoming file extension""" + + header: Optional[ConditionHeader] = None + """Match an incoming request header""" + + header_exists: Optional[ConditionHeaderExists] = None + """Match when an incoming request header is present""" + + http_method: Optional[ConditionHTTPMethod] = None + """Match the incoming HTTP method""" + + ip: Optional[ConditionIP] = None + """Match the incoming request against a single IP address""" + + ip_range: Optional[ConditionIPRange] = None + """Match the incoming request against an IP range""" + + organization: Optional[ConditionOrganization] = None + """ + Match the organization the request originated from, as determined by a WHOIS + lookup of the requesting IP + """ + + owner_types: Optional[ConditionOwnerTypes] = None + """ + Match the type of organization that owns the IP address making an incoming + request + """ + + request_rate: Optional[ConditionRequestRate] = None + """Match the rate at which requests come in that match certain conditions""" + + response_header: Optional[ConditionResponseHeader] = None + """Match a response header""" + + response_header_exists: Optional[ConditionResponseHeaderExists] = None + """Match when a response header is present""" + + session_request_count: Optional[ConditionSessionRequestCount] = None + """Match the number of dynamic page requests made in a WAAP session""" + + tags: Optional[ConditionTags] = None + """Matches requests based on specified tags""" + + url: Optional[ConditionURL] = None + """Match the incoming request URL""" + + user_agent: Optional[ConditionUserAgent] = None + """Match the user agent making the request""" + + user_defined_tags: Optional[ConditionUserDefinedTags] = None + """Matches requests based on user-defined tags""" + + +class WaapCustomRule(BaseModel): + """An WAAP rule applied to a domain""" + + id: int + """The unique identifier for the rule""" + + action: Action + """The action that the rule takes when triggered. + + Only one action can be set per rule. + """ + + conditions: List[Condition] + """The conditions required for the WAAP engine to trigger the rule. + + Rules may have between 1 and 5 conditions. All conditions must pass for the rule + to trigger + """ + + enabled: bool + """Whether or not the rule is enabled""" + + name: str + """The name assigned to the rule""" + + description: Optional[str] = None + """The description assigned to the rule""" diff --git a/src/gcore/types/waap/domains/waap_ddos_attack.py b/src/gcore/types/waap/domains/waap_ddos_attack.py new file mode 100644 index 00000000..fe777348 --- /dev/null +++ b/src/gcore/types/waap/domains/waap_ddos_attack.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from ...._models import BaseModel + +__all__ = ["WaapDDOSAttack"] + + +class WaapDDOSAttack(BaseModel): + end_time: Optional[datetime] = None + """End time of DDoS attack""" + + start_time: Optional[datetime] = None + """Start time of DDoS attack""" diff --git a/src/gcore/types/waap/domains/waap_ddos_info.py b/src/gcore/types/waap/domains/waap_ddos_info.py new file mode 100644 index 00000000..2633e56d --- /dev/null +++ b/src/gcore/types/waap/domains/waap_ddos_info.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["WaapDDOSInfo"] + + +class WaapDDOSInfo(BaseModel): + count: int + """The number of requests made""" + + identity: str + """The value for the grouped by type""" + + type: Literal["URL", "IP", "User-Agent"] diff --git a/src/gcore/types/waap/domains/waap_event_statistics.py b/src/gcore/types/waap/domains/waap_event_statistics.py new file mode 100644 index 00000000..90f2b1d1 --- /dev/null +++ b/src/gcore/types/waap/domains/waap_event_statistics.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel +from .waap_count_statistics import WaapCountStatistics +from .waap_blocked_statistics import WaapBlockedStatistics + +__all__ = ["WaapEventStatistics"] + + +class WaapEventStatistics(BaseModel): + """A collection of event metrics over a time span""" + + blocked: WaapBlockedStatistics + """A collection of total numbers of events with blocked results per criteria""" + + count: WaapCountStatistics + """A collection of total numbers of events per criteria""" diff --git a/src/gcore/types/waap/domains/waap_firewall_rule.py b/src/gcore/types/waap/domains/waap_firewall_rule.py new file mode 100644 index 00000000..9bad341c --- /dev/null +++ b/src/gcore/types/waap/domains/waap_firewall_rule.py @@ -0,0 +1,93 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["WaapFirewallRule", "Action", "ActionBlock", "Condition", "ConditionIP", "ConditionIPRange"] + + +class ActionBlock(BaseModel): + """ + WAAP block action behavior could be configured with response status code and action duration. + """ + + action_duration: Optional[str] = None + """How long a rule's block action will apply to subsequent requests. + + Can be specified in seconds or by using a numeral followed by 's', 'm', 'h', or + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. + """ + + status_code: Optional[Literal[403, 405, 418, 429]] = None + """A custom HTTP status code that the WAAP returns if a rule blocks a request""" + + +class Action(BaseModel): + """The action that the rule takes when triggered""" + + allow: Optional[Dict[str, object]] = None + """The WAAP allows the request""" + + block: Optional[ActionBlock] = None + """ + WAAP block action behavior could be configured with response status code and + action duration. + """ + + +class ConditionIP(BaseModel): + """Match the incoming request against a single IP address""" + + ip_address: str + """A single IPv4 or IPv6 address""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class ConditionIPRange(BaseModel): + """Match the incoming request against an IP range""" + + lower_bound: str + """The lower bound IPv4 or IPv6 address to match against""" + + upper_bound: str + """The upper bound IPv4 or IPv6 address to match against""" + + negation: Optional[bool] = None + """Whether or not to apply a boolean NOT operation to the rule's condition""" + + +class Condition(BaseModel): + """ + The criteria of an incoming web request and the models of the various values those criteria can take + """ + + ip: Optional[ConditionIP] = None + """Match the incoming request against a single IP address""" + + ip_range: Optional[ConditionIPRange] = None + """Match the incoming request against an IP range""" + + +class WaapFirewallRule(BaseModel): + id: int + """The unique identifier of the rule""" + + action: Action + """The action that the rule takes when triggered""" + + conditions: List[Condition] + """The condition required for the WAAP engine to trigger the rule.""" + + enabled: bool + """Whether or not the rule is enabled""" + + name: str + """The name assigned to the rule""" + + description: Optional[str] = None + """The description assigned to the rule""" diff --git a/src/gcore/types/waap/domains/waap_insight.py b/src/gcore/types/waap/domains/waap_insight.py new file mode 100644 index 00000000..070c8bd8 --- /dev/null +++ b/src/gcore/types/waap/domains/waap_insight.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["WaapInsight"] + + +class WaapInsight(BaseModel): + id: str + """A generated unique identifier for the insight""" + + description: str + """The description of the insight""" + + first_seen: datetime + """The date and time the insight was first seen in ISO 8601 format""" + + insight_type: str + """The slug of the insight type""" + + labels: Dict[str, str] + """A hash table of label names and values that apply to the insight""" + + last_seen: datetime + """The date and time the insight was last seen in ISO 8601 format""" + + last_status_change: datetime + """The date and time the insight was last seen in ISO 8601 format""" + + recommendation: str + """The recommended action to perform to resolve the insight""" + + status: Literal["OPEN", "ACKED", "CLOSED"] + """The status of the insight""" diff --git a/src/gcore/types/waap/domains/waap_insight_silence.py b/src/gcore/types/waap/domains/waap_insight_silence.py new file mode 100644 index 00000000..de1a7522 --- /dev/null +++ b/src/gcore/types/waap/domains/waap_insight_silence.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime + +from ...._models import BaseModel + +__all__ = ["WaapInsightSilence"] + + +class WaapInsightSilence(BaseModel): + id: str + """A generated unique identifier for the silence""" + + author: str + """The author of the silence""" + + comment: str + """A comment explaining the reason for the silence""" + + expire_at: Optional[datetime] = None + """The date and time the silence expires in ISO 8601 format""" + + insight_type: str + """The slug of the insight type""" + + labels: Dict[str, str] + """A hash table of label names and values that apply to the insight silence""" diff --git a/src/gcore/types/waap/domains/waap_request_details.py b/src/gcore/types/waap/domains/waap_request_details.py new file mode 100644 index 00000000..0eae8cfc --- /dev/null +++ b/src/gcore/types/waap/domains/waap_request_details.py @@ -0,0 +1,207 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["WaapRequestDetails", "CommonTag", "Network", "NetworkOrganization", "PatternMatchedTag", "UserAgent"] + + +class CommonTag(BaseModel): + """Common tag details""" + + description: str + """Tag description information""" + + display_name: str + """The tag's display name""" + + tag: str + """Tag name""" + + +class NetworkOrganization(BaseModel): + """Organization details""" + + name: str + """Organization name""" + + subnet: str + """Network range""" + + +class Network(BaseModel): + """Network details""" + + client_ip: str + """Client IP""" + + country: str + """Country code""" + + organization: NetworkOrganization + """Organization details""" + + +class PatternMatchedTag(BaseModel): + """Pattern matched tag details""" + + description: str + """Tag description information""" + + display_name: str + """The tag's display name""" + + execution_phase: str + """ + The phase in which the tag was triggered: access -> Request, `header_filter` -> + `response_header`, `body_filter` -> `response_body` + """ + + field: str + """The entity to which the variable that triggered the tag belong to. + + For example: `request_headers`, uri, cookies etc. + """ + + field_name: str + """The name of the variable which holds the value that triggered the tag""" + + pattern_name: str + """The name of the detected regexp pattern""" + + pattern_value: str + """The pattern which triggered the tag""" + + tag: str + """Tag name""" + + +class UserAgent(BaseModel): + """User agent""" + + base_browser: str + """User agent browser""" + + base_browser_version: str + """User agent browser version""" + + client: str + """Client from User agent header""" + + client_type: str + """User agent client type""" + + client_version: str + """User agent client version""" + + cpu: str + """User agent cpu""" + + device: str + """User agent device""" + + device_type: str + """User agent device type""" + + full_string: str + """User agent""" + + os: str + """User agent os""" + + rendering_engine: str + """User agent engine""" + + +class WaapRequestDetails(BaseModel): + """Request's details used when displaying a single request.""" + + id: str + """Request ID""" + + action: str + """Request action""" + + common_tags: List[CommonTag] + """List of common tags""" + + content_type: str + """Content type of request""" + + domain: str + """Domain name""" + + http_status_code: int + """Status code for http request""" + + http_version: str + """HTTP version of request""" + + incident_id: str + """ID of challenge that was generated""" + + method: str + """Request method""" + + network: Network + """Network details""" + + path: str + """Request path""" + + pattern_matched_tags: List[PatternMatchedTag] + """List of shield tags""" + + query_string: str + """The query string of the request""" + + reference_id: str + """Reference ID to identify user sanction""" + + request_headers: Dict[str, object] + """HTTP request headers""" + + request_time: datetime + """The time of the request""" + + request_type: str + """The type of the request that generated an event""" + + requested_domain: str + """The real domain name""" + + response_time: str + """Time took to process all request""" + + result: Literal["passed", "blocked", "suppressed", ""] + """The result of a request""" + + rule_id: str + """ID of the triggered rule""" + + rule_name: str + """Name of the triggered rule""" + + scheme: str + """The HTTP scheme of the request that generated an event""" + + session_id: str + """The session ID associated with the request.""" + + session_request_count: str + """The number requests in session""" + + traffic_types: List[str] + """List of traffic types""" + + user_agent: UserAgent + """User agent""" + + decision: Optional[Literal["passed", "allowed", "monitored", "blocked", ""]] = None + """The decision made for processing the request through the WAAP.""" + + optional_action: Optional[Literal["captcha", "challenge", ""]] = None + """An optional action that may be applied in addition to the primary decision.""" diff --git a/src/gcore/types/waap/domains/waap_request_summary.py b/src/gcore/types/waap/domains/waap_request_summary.py new file mode 100644 index 00000000..68be1c90 --- /dev/null +++ b/src/gcore/types/waap/domains/waap_request_summary.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["WaapRequestSummary"] + + +class WaapRequestSummary(BaseModel): + """Request summary used when displaying a list of requests""" + + id: str + """Request's unique id""" + + action: str + """Action of the triggered rule""" + + client_ip: str + """Client's IP address.""" + + country: str + """Country code""" + + decision: Literal["passed", "allowed", "monitored", "blocked", ""] + """The decision made for processing the request through the WAAP.""" + + domain: str + """Domain name""" + + domain_id: int + """Domain ID""" + + method: str + """HTTP method""" + + optional_action: Literal["captcha", "challenge", ""] + """An optional action that may be applied in addition to the primary decision.""" + + organization: str + """Organization""" + + path: str + """Request path""" + + reference_id: str + """The reference ID to a sanction that was given to a user.""" + + request_time: int + """The UNIX timestamp in ms of the date a set of traffic counters was recorded""" + + result: Literal["passed", "blocked", "suppressed", ""] + + rule_id: str + """The ID of the triggered rule.""" + + rule_name: str + """Name of the triggered rule""" + + status_code: int + """Status code for http request""" + + traffic_types: str + """Comma separated list of traffic types.""" + + user_agent: str + """User agent""" + + user_agent_client: str + """Client from parsed User agent header""" + + session_id: Optional[str] = None + """The session ID associated with the request.""" diff --git a/src/gcore/types/waap/domains/waap_task_id.py b/src/gcore/types/waap/domains/waap_task_id.py new file mode 100644 index 00000000..22f383c7 --- /dev/null +++ b/src/gcore/types/waap/domains/waap_task_id.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["WaapTaskID"] + + +class WaapTaskID(BaseModel): + """Response model for the task result ID""" + + id: str + """The task ID""" diff --git a/src/gcore/types/waap/domains/waap_traffic_metrics.py b/src/gcore/types/waap/domains/waap_traffic_metrics.py new file mode 100644 index 00000000..b87d6c4b --- /dev/null +++ b/src/gcore/types/waap/domains/waap_traffic_metrics.py @@ -0,0 +1,70 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ...._models import BaseModel + +__all__ = ["WaapTrafficMetrics"] + + +class WaapTrafficMetrics(BaseModel): + """Represents the traffic metrics for a domain at a given time window""" + + timestamp: int + """UNIX timestamp indicating when the traffic data was recorded""" + + ajax: Optional[int] = None + """Number of AJAX requests made""" + + api: Optional[int] = None + """Number of API requests made""" + + custom_allowed: Optional[int] = FieldInfo(alias="customAllowed", default=None) + """Number of requests allowed through custom rules""" + + custom_blocked: Optional[int] = FieldInfo(alias="customBlocked", default=None) + """Number of requests blocked due to custom rules""" + + ddos_blocked: Optional[int] = FieldInfo(alias="ddosBlocked", default=None) + """Number of DDoS attack attempts successfully blocked""" + + monitored: Optional[int] = None + """Number of requests triggering monitoring actions""" + + origin2xx: Optional[int] = None + """Number of successful HTTP 2xx responses from the origin server""" + + origin3xx: Optional[int] = None + """Number of HTTP 3xx redirects issued by the origin server""" + + origin_error4xx: Optional[int] = FieldInfo(alias="originError4xx", default=None) + """Number of HTTP 4xx errors from the origin server""" + + origin_error5xx: Optional[int] = FieldInfo(alias="originError5xx", default=None) + """Number of HTTP 5xx errors from the origin server""" + + origin_timeout: Optional[int] = FieldInfo(alias="originTimeout", default=None) + """Number of timeouts experienced at the origin server""" + + passed_to_origin: Optional[int] = FieldInfo(alias="passedToOrigin", default=None) + """Number of requests served directly by the origin server""" + + policy_allowed: Optional[int] = FieldInfo(alias="policyAllowed", default=None) + """Number of requests allowed by security policies""" + + policy_blocked: Optional[int] = FieldInfo(alias="policyBlocked", default=None) + """Number of requests blocked by security policies""" + + response_time: Optional[int] = FieldInfo(alias="responseTime", default=None) + """Average origin server response time in milliseconds""" + + static: Optional[int] = None + """Number of static asset requests""" + + total: Optional[int] = None + """Total number of requests""" + + uncategorized: Optional[int] = None + """Requests resulting in neither blocks nor sanctions""" diff --git a/src/gcore/types/waap/insight_list_types_params.py b/src/gcore/types/waap/insight_list_types_params.py new file mode 100644 index 00000000..534f2cc2 --- /dev/null +++ b/src/gcore/types/waap/insight_list_types_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["InsightListTypesParams"] + + +class InsightListTypesParams(TypedDict, total=False): + insight_frequency: Optional[int] + """Filter by the frequency of the insight type""" + + limit: int + """Number of items to return""" + + name: Optional[str] + """Filter by the name of the insight type""" + + offset: int + """Number of items to skip""" + + ordering: Literal["name", "-name", "slug", "-slug", "insight_frequency", "-insight_frequency"] + """Sort the response by given field.""" + + slug: Optional[str] + """Filter by the slug of the insight type""" diff --git a/src/gcore/types/waap/ip_info/__init__.py b/src/gcore/types/waap/ip_info/__init__.py new file mode 100644 index 00000000..ed4c6baa --- /dev/null +++ b/src/gcore/types/waap/ip_info/__init__.py @@ -0,0 +1,6 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .metric_list_params import MetricListParams as MetricListParams +from .waap_ip_info_counts import WaapIPInfoCounts as WaapIPInfoCounts diff --git a/src/gcore/types/waap/ip_info/metric_list_params.py b/src/gcore/types/waap/ip_info/metric_list_params.py new file mode 100644 index 00000000..bfa030d6 --- /dev/null +++ b/src/gcore/types/waap/ip_info/metric_list_params.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +__all__ = ["MetricListParams"] + + +class MetricListParams(TypedDict, total=False): + ip: Required[str] + """The IP address to check""" + + domain_id: Optional[int] + """The identifier for a domain. + + When specified, the response will exclusively contain data pertinent to the + indicated domain, filtering out information from other domains. + """ diff --git a/src/gcore/types/waap/ip_info/waap_ip_info_counts.py b/src/gcore/types/waap/ip_info/waap_ip_info_counts.py new file mode 100644 index 00000000..7f1229fd --- /dev/null +++ b/src/gcore/types/waap/ip_info/waap_ip_info_counts.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["WaapIPInfoCounts"] + + +class WaapIPInfoCounts(BaseModel): + blocked_requests: int + """The number of requests from the IP address that were blocked""" + + total_requests: int + """The total number of requests made by the IP address""" + + unique_sessions: int + """The number of unique sessions from the IP address""" diff --git a/src/gcore/types/waap/ip_info_get_attack_time_series_params.py b/src/gcore/types/waap/ip_info_get_attack_time_series_params.py new file mode 100644 index 00000000..f4705e0c --- /dev/null +++ b/src/gcore/types/waap/ip_info_get_attack_time_series_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["IPInfoGetAttackTimeSeriesParams"] + + +class IPInfoGetAttackTimeSeriesParams(TypedDict, total=False): + ip: Required[str] + """The IP address to check""" diff --git a/src/gcore/types/waap/ip_info_get_attack_time_series_response.py b/src/gcore/types/waap/ip_info_get_attack_time_series_response.py new file mode 100644 index 00000000..71faeea9 --- /dev/null +++ b/src/gcore/types/waap/ip_info_get_attack_time_series_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .waap_time_series_attack import WaapTimeSeriesAttack + +__all__ = ["IPInfoGetAttackTimeSeriesResponse"] + +IPInfoGetAttackTimeSeriesResponse: TypeAlias = List[WaapTimeSeriesAttack] diff --git a/src/gcore/types/waap/ip_info_get_blocked_requests_params.py b/src/gcore/types/waap/ip_info_get_blocked_requests_params.py new file mode 100644 index 00000000..eb9585dc --- /dev/null +++ b/src/gcore/types/waap/ip_info_get_blocked_requests_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["IPInfoGetBlockedRequestsParams"] + + +class IPInfoGetBlockedRequestsParams(TypedDict, total=False): + domain_id: Required[int] + """The identifier for a domain. + + When specified, the response will exclusively contain data pertinent to the + indicated domain, filtering out information from other domains. + """ + + ip: Required[str] + """The IP address to check""" diff --git a/src/gcore/types/waap/ip_info_get_blocked_requests_response.py b/src/gcore/types/waap/ip_info_get_blocked_requests_response.py new file mode 100644 index 00000000..5cecb447 --- /dev/null +++ b/src/gcore/types/waap/ip_info_get_blocked_requests_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .waap_rule_blocked_requests import WaapRuleBlockedRequests + +__all__ = ["IPInfoGetBlockedRequestsResponse"] + +IPInfoGetBlockedRequestsResponse: TypeAlias = List[WaapRuleBlockedRequests] diff --git a/src/gcore/types/waap/ip_info_get_ddos_attack_series_params.py b/src/gcore/types/waap/ip_info_get_ddos_attack_series_params.py new file mode 100644 index 00000000..7d28ee62 --- /dev/null +++ b/src/gcore/types/waap/ip_info_get_ddos_attack_series_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["IPInfoGetDDOSAttackSeriesParams"] + + +class IPInfoGetDDOSAttackSeriesParams(TypedDict, total=False): + ip: Required[str] + """The IP address to check""" diff --git a/src/gcore/types/waap/ip_info_get_ip_info_params.py b/src/gcore/types/waap/ip_info_get_ip_info_params.py new file mode 100644 index 00000000..549abb8b --- /dev/null +++ b/src/gcore/types/waap/ip_info_get_ip_info_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["IPInfoGetIPInfoParams"] + + +class IPInfoGetIPInfoParams(TypedDict, total=False): + ip: Required[str] + """The IP address to check""" diff --git a/src/gcore/types/waap/ip_info_get_top_urls_params.py b/src/gcore/types/waap/ip_info_get_top_urls_params.py new file mode 100644 index 00000000..1184ecaf --- /dev/null +++ b/src/gcore/types/waap/ip_info_get_top_urls_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["IPInfoGetTopURLsParams"] + + +class IPInfoGetTopURLsParams(TypedDict, total=False): + domain_id: Required[int] + """The identifier for a domain. + + When specified, the response will exclusively contain data pertinent to the + indicated domain, filtering out information from other domains. + """ + + ip: Required[str] + """The IP address to check""" diff --git a/src/gcore/types/waap/ip_info_get_top_urls_response.py b/src/gcore/types/waap/ip_info_get_top_urls_response.py new file mode 100644 index 00000000..76dc6cdb --- /dev/null +++ b/src/gcore/types/waap/ip_info_get_top_urls_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .waap_top_url import WaapTopURL + +__all__ = ["IPInfoGetTopURLsResponse"] + +IPInfoGetTopURLsResponse: TypeAlias = List[WaapTopURL] diff --git a/src/gcore/types/waap/ip_info_get_top_user_agents_params.py b/src/gcore/types/waap/ip_info_get_top_user_agents_params.py new file mode 100644 index 00000000..162f4097 --- /dev/null +++ b/src/gcore/types/waap/ip_info_get_top_user_agents_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["IPInfoGetTopUserAgentsParams"] + + +class IPInfoGetTopUserAgentsParams(TypedDict, total=False): + domain_id: Required[int] + """The identifier for a domain. + + When specified, the response will exclusively contain data pertinent to the + indicated domain, filtering out information from other domains. + """ + + ip: Required[str] + """The IP address to check""" diff --git a/src/gcore/types/waap/ip_info_get_top_user_agents_response.py b/src/gcore/types/waap/ip_info_get_top_user_agents_response.py new file mode 100644 index 00000000..883a4088 --- /dev/null +++ b/src/gcore/types/waap/ip_info_get_top_user_agents_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .waap_top_user_agent import WaapTopUserAgent + +__all__ = ["IPInfoGetTopUserAgentsResponse"] + +IPInfoGetTopUserAgentsResponse: TypeAlias = List[WaapTopUserAgent] diff --git a/src/gcore/types/waap/ip_info_get_top_user_sessions_params.py b/src/gcore/types/waap/ip_info_get_top_user_sessions_params.py new file mode 100644 index 00000000..d9988114 --- /dev/null +++ b/src/gcore/types/waap/ip_info_get_top_user_sessions_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["IPInfoGetTopUserSessionsParams"] + + +class IPInfoGetTopUserSessionsParams(TypedDict, total=False): + domain_id: Required[int] + """The identifier for a domain. + + When specified, the response will exclusively contain data pertinent to the + indicated domain, filtering out information from other domains. + """ + + ip: Required[str] + """The IP address to check""" diff --git a/src/gcore/types/waap/ip_info_get_top_user_sessions_response.py b/src/gcore/types/waap/ip_info_get_top_user_sessions_response.py new file mode 100644 index 00000000..21dbbf07 --- /dev/null +++ b/src/gcore/types/waap/ip_info_get_top_user_sessions_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .waap_top_session import WaapTopSession + +__all__ = ["IPInfoGetTopUserSessionsResponse"] + +IPInfoGetTopUserSessionsResponse: TypeAlias = List[WaapTopSession] diff --git a/src/gcore/types/waap/ip_info_list_attacked_countries_params.py b/src/gcore/types/waap/ip_info_list_attacked_countries_params.py new file mode 100644 index 00000000..f3f4d4a5 --- /dev/null +++ b/src/gcore/types/waap/ip_info_list_attacked_countries_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["IPInfoListAttackedCountriesParams"] + + +class IPInfoListAttackedCountriesParams(TypedDict, total=False): + ip: Required[str] + """The IP address to check""" diff --git a/src/gcore/types/waap/ip_info_list_attacked_countries_response.py b/src/gcore/types/waap/ip_info_list_attacked_countries_response.py new file mode 100644 index 00000000..95b88508 --- /dev/null +++ b/src/gcore/types/waap/ip_info_list_attacked_countries_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .waap_ip_country_attack import WaapIPCountryAttack + +__all__ = ["IPInfoListAttackedCountriesResponse"] + +IPInfoListAttackedCountriesResponse: TypeAlias = List[WaapIPCountryAttack] diff --git a/src/gcore/types/waap/organization_list_params.py b/src/gcore/types/waap/organization_list_params.py new file mode 100644 index 00000000..979b7b27 --- /dev/null +++ b/src/gcore/types/waap/organization_list_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["OrganizationListParams"] + + +class OrganizationListParams(TypedDict, total=False): + limit: int + """Number of items to return""" + + name: str + """Filter organizations by their name. Supports '\\**' as a wildcard character.""" + + offset: int + """Number of items to skip""" + + ordering: Optional[Literal["name", "id", "-name", "-id"]] + """Determine the field to order results by""" diff --git a/src/gcore/types/waap/statistic_get_usage_series_params.py b/src/gcore/types/waap/statistic_get_usage_series_params.py new file mode 100644 index 00000000..104e23a9 --- /dev/null +++ b/src/gcore/types/waap/statistic_get_usage_series_params.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["StatisticGetUsageSeriesParams"] + + +class StatisticGetUsageSeriesParams(TypedDict, total=False): + from_: Required[Annotated[Union[str, datetime], PropertyInfo(alias="from", format="iso8601")]] + """Beginning of the requested time period (ISO 8601 format, UTC)""" + + granularity: Required[Literal["1h", "1d"]] + """Duration of the time blocks into which the data will be divided.""" + + metrics: Required[List[Literal["total_bytes", "total_requests"]]] + """List of metric types to retrieve statistics for.""" + + to: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """End of the requested time period (ISO 8601 format, UTC)""" diff --git a/src/gcore/types/waap/tag_list_params.py b/src/gcore/types/waap/tag_list_params.py new file mode 100644 index 00000000..5ff06753 --- /dev/null +++ b/src/gcore/types/waap/tag_list_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["TagListParams"] + + +class TagListParams(TypedDict, total=False): + limit: int + """Number of items to return""" + + name: str + """Filter tags by their name. Supports '\\**' as a wildcard character.""" + + offset: int + """Number of items to skip""" + + ordering: Optional[Literal["name", "readable_name", "reserved", "-name", "-readable_name", "-reserved"]] + """Determine the field to order results by""" + + readable_name: str + """Filter tags by their readable name. Supports '\\**' as a wildcard character.""" + + reserved: bool + """Filter to include only reserved tags.""" diff --git a/src/gcore/types/waap/waap_advanced_rule_descriptor.py b/src/gcore/types/waap/waap_advanced_rule_descriptor.py new file mode 100644 index 00000000..0aac47d5 --- /dev/null +++ b/src/gcore/types/waap/waap_advanced_rule_descriptor.py @@ -0,0 +1,55 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["WaapAdvancedRuleDescriptor", "Attr", "AttrArg"] + + +class AttrArg(BaseModel): + """An argument of a descriptor's object""" + + name: str + """The argument's name""" + + type: str + """The argument's type""" + + description: Optional[str] = None + """The argument's description""" + + +class Attr(BaseModel): + """An attribute of a descriptor's object""" + + name: str + """The attribute's name""" + + type: str + """The attribute's type""" + + args: Optional[List[AttrArg]] = None + """A list of arguments for the attribute""" + + description: Optional[str] = None + """The attribute's description""" + + hint: Optional[str] = None + """The attribute's hint""" + + +class WaapAdvancedRuleDescriptor(BaseModel): + """Advanced rules descriptor object""" + + name: str + """The object's name""" + + type: str + """The object's type""" + + attrs: Optional[List[Attr]] = None + """The object's attributes list""" + + description: Optional[str] = None + """The object's description""" diff --git a/src/gcore/types/waap/waap_advanced_rule_descriptor_list.py b/src/gcore/types/waap/waap_advanced_rule_descriptor_list.py new file mode 100644 index 00000000..5af6cb73 --- /dev/null +++ b/src/gcore/types/waap/waap_advanced_rule_descriptor_list.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .waap_advanced_rule_descriptor import WaapAdvancedRuleDescriptor + +__all__ = ["WaapAdvancedRuleDescriptorList"] + + +class WaapAdvancedRuleDescriptorList(BaseModel): + """A response from a request to retrieve an advanced rules descriptor""" + + version: str + """The descriptor's version""" + + objects: Optional[List[WaapAdvancedRuleDescriptor]] = None diff --git a/src/gcore/types/waap/waap_custom_page_preview.py b/src/gcore/types/waap/waap_custom_page_preview.py new file mode 100644 index 00000000..cae580b3 --- /dev/null +++ b/src/gcore/types/waap/waap_custom_page_preview.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["WaapCustomPagePreview"] + + +class WaapCustomPagePreview(BaseModel): + html: str + """HTML content of the custom page""" diff --git a/src/gcore/types/waap/waap_custom_page_set.py b/src/gcore/types/waap/waap_custom_page_set.py new file mode 100644 index 00000000..bade75d9 --- /dev/null +++ b/src/gcore/types/waap/waap_custom_page_set.py @@ -0,0 +1,136 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["WaapCustomPageSet", "Block", "BlockCsrf", "Captcha", "CookieDisabled", "Handshake", "JavascriptDisabled"] + + +class Block(BaseModel): + enabled: bool + """Indicates whether the custom custom page is active or inactive""" + + header: Optional[str] = None + """The text to display in the header of the custom page""" + + logo: Optional[str] = None + """ + Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + """ + + text: Optional[str] = None + """The text to display in the body of the custom page""" + + title: Optional[str] = None + """The text to display in the title of the custom page""" + + +class BlockCsrf(BaseModel): + enabled: bool + """Indicates whether the custom custom page is active or inactive""" + + header: Optional[str] = None + """The text to display in the header of the custom page""" + + logo: Optional[str] = None + """ + Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + """ + + text: Optional[str] = None + """The text to display in the body of the custom page""" + + title: Optional[str] = None + """The text to display in the title of the custom page""" + + +class Captcha(BaseModel): + enabled: bool + """Indicates whether the custom custom page is active or inactive""" + + error: Optional[str] = None + """Error message""" + + header: Optional[str] = None + """The text to display in the header of the custom page""" + + logo: Optional[str] = None + """ + Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + """ + + text: Optional[str] = None + """The text to display in the body of the custom page""" + + title: Optional[str] = None + """The text to display in the title of the custom page""" + + +class CookieDisabled(BaseModel): + enabled: bool + """Indicates whether the custom custom page is active or inactive""" + + header: Optional[str] = None + """The text to display in the header of the custom page""" + + text: Optional[str] = None + """The text to display in the body of the custom page""" + + +class Handshake(BaseModel): + enabled: bool + """Indicates whether the custom custom page is active or inactive""" + + header: Optional[str] = None + """The text to display in the header of the custom page""" + + logo: Optional[str] = None + """ + Supported image types are JPEG, PNG and JPG, size is limited to width 450px, + height 130px. This should be a base 64 encoding of the full HTML img tag + compatible image, with the header included. + """ + + title: Optional[str] = None + """The text to display in the title of the custom page""" + + +class JavascriptDisabled(BaseModel): + enabled: bool + """Indicates whether the custom custom page is active or inactive""" + + header: Optional[str] = None + """The text to display in the header of the custom page""" + + text: Optional[str] = None + """The text to display in the body of the custom page""" + + +class WaapCustomPageSet(BaseModel): + id: int + """The ID of the custom page set""" + + name: str + """Name of the custom page set""" + + block: Optional[Block] = None + + block_csrf: Optional[BlockCsrf] = None + + captcha: Optional[Captcha] = None + + cookie_disabled: Optional[CookieDisabled] = None + + domains: Optional[List[int]] = None + """List of domain IDs that are associated with this page set""" + + handshake: Optional[Handshake] = None + + javascript_disabled: Optional[JavascriptDisabled] = None diff --git a/src/gcore/types/waap/waap_detailed_domain.py b/src/gcore/types/waap/waap_detailed_domain.py new file mode 100644 index 00000000..e76b62b1 --- /dev/null +++ b/src/gcore/types/waap/waap_detailed_domain.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["WaapDetailedDomain", "Quotas"] + + +class Quotas(BaseModel): + allowed: int + """The maximum allowed number of this resource""" + + current: int + """The current number of this resource""" + + +class WaapDetailedDomain(BaseModel): + """Represents a WAAP domain, serving as a singular unit within the WAAP + service. + + Each domain functions autonomously, possessing its own set of rules and + configurations to manage web application firewall settings and + behaviors. + """ + + id: int + """The domain ID""" + + created_at: datetime + """The date and time the domain was created in ISO 8601 format""" + + custom_page_set: Optional[int] = None + """The ID of the custom page set""" + + name: str + """The domain name""" + + status: Literal["active", "bypass", "monitor", "locked"] + """The different statuses a domain can have""" + + quotas: Optional[Dict[str, Quotas]] = None + """Domain level quotas""" diff --git a/src/gcore/types/waap/waap_domain_api_settings.py b/src/gcore/types/waap/waap_domain_api_settings.py new file mode 100644 index 00000000..0d6c6615 --- /dev/null +++ b/src/gcore/types/waap/waap_domain_api_settings.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["WaapDomainAPISettings"] + + +class WaapDomainAPISettings(BaseModel): + """API settings of a domain""" + + api_urls: Optional[List[str]] = None + """The API URLs for a domain. + + If your domain has a common base URL for all API paths, it can be set here + """ + + is_api: Optional[bool] = None + """Indicates if the domain is an API domain. + + All requests to an API domain are treated as API requests. If this is set to + true then the `api_urls` field is ignored. + """ diff --git a/src/gcore/types/waap/waap_domain_ddos_settings.py b/src/gcore/types/waap/waap_domain_ddos_settings.py new file mode 100644 index 00000000..6111d794 --- /dev/null +++ b/src/gcore/types/waap/waap_domain_ddos_settings.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["WaapDomainDDOSSettings"] + + +class WaapDomainDDOSSettings(BaseModel): + """DDoS settings for a domain.""" + + burst_threshold: Optional[int] = None + """The burst threshold detects sudden rises in traffic. + + If it is met and the number of requests is at least five times the last 2-second + interval, DDoS protection will activate. Default is 1000. + """ + + global_threshold: Optional[int] = None + """ + The global threshold is responsible for identifying DDoS attacks with a slow + rise in traffic. If the threshold is met and the current number of requests is + at least double that of the previous 10-second window, DDoS protection will + activate. Default is 5000. + """ + + sub_second_threshold: Optional[int] = None + """ + The sub-second threshold protects WAAP servers against attacks from traffic + bursts. When this threshold is reached, the DDoS mode will activate on the + affected WAAP server, not the whole WAAP cluster. Default is 50. + """ diff --git a/src/gcore/types/waap/waap_domain_settings_model.py b/src/gcore/types/waap/waap_domain_settings_model.py new file mode 100644 index 00000000..96ee2d3e --- /dev/null +++ b/src/gcore/types/waap/waap_domain_settings_model.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel +from .waap_domain_api_settings import WaapDomainAPISettings +from .waap_domain_ddos_settings import WaapDomainDDOSSettings + +__all__ = ["WaapDomainSettingsModel"] + + +class WaapDomainSettingsModel(BaseModel): + """Settings for a domain.""" + + api: WaapDomainAPISettings + """API settings of a domain""" + + ddos: WaapDomainDDOSSettings + """DDoS settings for a domain.""" diff --git a/src/gcore/types/waap/waap_get_account_overview_response.py b/src/gcore/types/waap/waap_get_account_overview_response.py new file mode 100644 index 00000000..079eb6f0 --- /dev/null +++ b/src/gcore/types/waap/waap_get_account_overview_response.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional + +from ..._models import BaseModel + +__all__ = ["WaapGetAccountOverviewResponse", "Quotas", "Service"] + + +class Quotas(BaseModel): + allowed: int + """The maximum allowed number of this resource""" + + current: int + """The current number of this resource""" + + +class Service(BaseModel): + """Information about the WAAP service status""" + + enabled: bool + """Whether the service is enabled""" + + +class WaapGetAccountOverviewResponse(BaseModel): + """Represents the WAAP service information for a client""" + + id: Optional[int] = None + """The client ID""" + + features: List[str] + """List of enabled features""" + + quotas: Dict[str, Quotas] + """Quotas for the client""" + + service: Service + """Information about the WAAP service status""" diff --git a/src/gcore/types/waap/waap_insight_type.py b/src/gcore/types/waap/waap_insight_type.py new file mode 100644 index 00000000..29055cc0 --- /dev/null +++ b/src/gcore/types/waap/waap_insight_type.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel + +__all__ = ["WaapInsightType"] + + +class WaapInsightType(BaseModel): + description: str + """The description of the insight type""" + + insight_frequency: int + """The frequency of the insight type""" + + insight_grouping_dimensions: List[str] + """The grouping dimensions of the insight type""" + + insight_template: str + """The insight template""" + + labels: List[str] + """The labels of the insight type""" + + name: str + """The name of the insight type""" + + recommendation_template: str + """The recommendation template""" + + slug: str + """The slug of the insight type""" diff --git a/src/gcore/types/waap/waap_ip_country_attack.py b/src/gcore/types/waap/waap_ip_country_attack.py new file mode 100644 index 00000000..cba448a8 --- /dev/null +++ b/src/gcore/types/waap/waap_ip_country_attack.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["WaapIPCountryAttack"] + + +class WaapIPCountryAttack(BaseModel): + count: int + """The number of attacks from the specified IP address to the country""" + + country: str + """ + An ISO 3166-1 alpha-2 formatted string representing the country that was + attacked + """ diff --git a/src/gcore/types/waap/waap_ip_ddos_info_model.py b/src/gcore/types/waap/waap_ip_ddos_info_model.py new file mode 100644 index 00000000..14450304 --- /dev/null +++ b/src/gcore/types/waap/waap_ip_ddos_info_model.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel + +__all__ = ["WaapIPDDOSInfoModel", "TimeSeries"] + + +class TimeSeries(BaseModel): + count: int + """The number of attacks""" + + timestamp: int + """The timestamp of the time series item as a POSIX timestamp""" + + +class WaapIPDDOSInfoModel(BaseModel): + botnet_client: bool + """Indicates if the IP is tagged as a botnet client""" + + time_series: List[TimeSeries] + """The time series data for the DDoS attacks from the IP address""" diff --git a/src/gcore/types/waap/waap_ip_info.py b/src/gcore/types/waap/waap_ip_info.py new file mode 100644 index 00000000..e1ace869 --- /dev/null +++ b/src/gcore/types/waap/waap_ip_info.py @@ -0,0 +1,59 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["WaapIPInfo", "Whois"] + + +class Whois(BaseModel): + """The WHOIS information for the IP address""" + + abuse_mail: Optional[str] = None + """The abuse mail""" + + cidr: Optional[int] = None + """The CIDR""" + + country: Optional[str] = None + """The country""" + + net_description: Optional[str] = None + """The network description""" + + net_name: Optional[str] = None + """The network name""" + + net_range: Optional[str] = None + """The network range""" + + net_type: Optional[str] = None + """The network type""" + + org_id: Optional[str] = None + """The organization ID""" + + org_name: Optional[str] = None + """The organization name""" + + owner_type: Optional[str] = None + """The owner type""" + + rir: Optional[str] = None + """The RIR""" + + state: Optional[str] = None + """The state""" + + +class WaapIPInfo(BaseModel): + risk_score: Literal["NO_RISK", "LOW", "MEDIUM", "HIGH", "EXTREME", "NOT_ENOUGH_DATA"] + """The risk score of the IP address""" + + tags: List[str] + """The tags associated with the IP address that affect the risk score""" + + whois: Whois + """The WHOIS information for the IP address""" diff --git a/src/gcore/types/waap/waap_organization.py b/src/gcore/types/waap/waap_organization.py new file mode 100644 index 00000000..aa851e76 --- /dev/null +++ b/src/gcore/types/waap/waap_organization.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["WaapOrganization"] + + +class WaapOrganization(BaseModel): + """Represents an IP range owner organization""" + + id: int + """The ID of an organization""" + + name: str + """The name of an organization""" diff --git a/src/gcore/types/waap/waap_policy_mode.py b/src/gcore/types/waap/waap_policy_mode.py new file mode 100644 index 00000000..14faca49 --- /dev/null +++ b/src/gcore/types/waap/waap_policy_mode.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["WaapPolicyMode"] + + +class WaapPolicyMode(BaseModel): + """Represents the mode of a security rule.""" + + mode: bool + """Indicates if the security rule is active""" diff --git a/src/gcore/types/waap/waap_rule_blocked_requests.py b/src/gcore/types/waap/waap_rule_blocked_requests.py new file mode 100644 index 00000000..c07342eb --- /dev/null +++ b/src/gcore/types/waap/waap_rule_blocked_requests.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["WaapRuleBlockedRequests"] + + +class WaapRuleBlockedRequests(BaseModel): + action: str + """The action taken by the rule""" + + count: int + """The number of requests blocked by the rule""" + + rule_name: str + """The name of the rule that blocked the request""" diff --git a/src/gcore/types/waap/waap_rule_set.py b/src/gcore/types/waap/waap_rule_set.py new file mode 100644 index 00000000..99f01433 --- /dev/null +++ b/src/gcore/types/waap/waap_rule_set.py @@ -0,0 +1,70 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["WaapRuleSet", "Tag", "Rule"] + + +class Tag(BaseModel): + """A single tag associated with a rule set.""" + + id: int + """Identifier of the tag.""" + + description: str + """Detailed description of the tag.""" + + name: str + """Name of the tag.""" + + +class Rule(BaseModel): + """Represents a configurable WAAP security rule, also known as a policy.""" + + id: str + """Unique identifier for the security rule""" + + action: Literal["Allow", "Block", "Captcha", "Gateway", "Handshake", "Monitor", "Composite"] + """Specifies the action taken by the WAAP upon rule activation""" + + description: str + """Detailed description of the security rule""" + + group: str + """The rule set group name to which the rule belongs""" + + mode: bool + """Indicates if the security rule is active""" + + name: str + """Name of the security rule""" + + rule_set_id: int + """Identifier of the rule set to which the rule belongs""" + + +class WaapRuleSet(BaseModel): + """Represents a custom rule set.""" + + id: int + """Identifier of the rule set.""" + + description: str + """Detailed description of the rule set.""" + + is_active: bool + """Indicates if the rule set is currently active.""" + + name: str + """Name of the rule set.""" + + tags: List[Tag] + """Collection of tags associated with the rule set.""" + + resource_slug: Optional[str] = None + """The resource slug associated with the rule set.""" + + rules: Optional[List[Rule]] = None diff --git a/src/gcore/types/waap/waap_statistic_item.py b/src/gcore/types/waap/waap_statistic_item.py new file mode 100644 index 00000000..925cb6d3 --- /dev/null +++ b/src/gcore/types/waap/waap_statistic_item.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["WaapStatisticItem"] + + +class WaapStatisticItem(BaseModel): + """Response model for the statistics item""" + + date_time: datetime + """The date and time for the statistic in ISO 8601 format""" + + value: int + """The value for the statistic. + + If there is no data for the given time, the value will be 0. + """ diff --git a/src/gcore/types/waap/waap_statistics_series.py b/src/gcore/types/waap/waap_statistics_series.py new file mode 100644 index 00000000..d645dc66 --- /dev/null +++ b/src/gcore/types/waap/waap_statistics_series.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .waap_statistic_item import WaapStatisticItem + +__all__ = ["WaapStatisticsSeries"] + + +class WaapStatisticsSeries(BaseModel): + """Response model for the statistics series""" + + total_bytes: Optional[List[WaapStatisticItem]] = None + """Will be returned if `total_bytes` is requested in the metrics parameter""" + + total_requests: Optional[List[WaapStatisticItem]] = None + """Will be included if `total_requests` is requested in the metrics parameter""" diff --git a/src/gcore/types/waap/waap_summary_domain.py b/src/gcore/types/waap/waap_summary_domain.py new file mode 100644 index 00000000..b5186b37 --- /dev/null +++ b/src/gcore/types/waap/waap_summary_domain.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["WaapSummaryDomain"] + + +class WaapSummaryDomain(BaseModel): + """Represents a WAAP domain when getting a list of domains.""" + + id: int + """The domain ID""" + + created_at: datetime + """The date and time the domain was created in ISO 8601 format""" + + custom_page_set: Optional[int] = None + """The ID of the custom page set""" + + name: str + """The domain name""" + + status: Literal["active", "bypass", "monitor", "locked"] + """The different statuses a domain can have""" diff --git a/src/gcore/types/waap/waap_tag.py b/src/gcore/types/waap/waap_tag.py new file mode 100644 index 00000000..fe934227 --- /dev/null +++ b/src/gcore/types/waap/waap_tag.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["WaapTag"] + + +class WaapTag(BaseModel): + """ + Tags provide shortcuts for the rules used in WAAP policies for the creation of more complex WAAP rules. + """ + + description: str + """A tag's human readable description""" + + name: str + """The name of a tag that should be used in a WAAP rule condition""" + + readable_name: str + """The display name of the tag""" diff --git a/src/gcore/types/waap/waap_time_series_attack.py b/src/gcore/types/waap/waap_time_series_attack.py new file mode 100644 index 00000000..6b65e32e --- /dev/null +++ b/src/gcore/types/waap/waap_time_series_attack.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel + +__all__ = ["WaapTimeSeriesAttack", "Value"] + + +class Value(BaseModel): + count: int + """The number of attacks""" + + timestamp: int + """The timestamp of the time series item as a POSIX timestamp""" + + +class WaapTimeSeriesAttack(BaseModel): + attack_type: str + """The type of attack""" + + values: List[Value] + """The time series data""" diff --git a/src/gcore/types/waap/waap_top_session.py b/src/gcore/types/waap/waap_top_session.py new file mode 100644 index 00000000..55760e27 --- /dev/null +++ b/src/gcore/types/waap/waap_top_session.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["WaapTopSession"] + + +class WaapTopSession(BaseModel): + blocked: int + """The number of blocked requests in the session""" + + duration: float + """The duration of the session in seconds""" + + requests: int + """The number of requests in the session""" + + session_id: str + """The session ID""" + + start_time: datetime + """The start time of the session as a POSIX timestamp""" diff --git a/src/gcore/types/waap/waap_top_url.py b/src/gcore/types/waap/waap_top_url.py new file mode 100644 index 00000000..88d761f8 --- /dev/null +++ b/src/gcore/types/waap/waap_top_url.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["WaapTopURL"] + + +class WaapTopURL(BaseModel): + count: int + """The number of attacks to the URL""" + + url: str + """The URL that was attacked""" diff --git a/src/gcore/types/waap/waap_top_user_agent.py b/src/gcore/types/waap/waap_top_user_agent.py new file mode 100644 index 00000000..93d28557 --- /dev/null +++ b/src/gcore/types/waap/waap_top_user_agent.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["WaapTopUserAgent"] + + +class WaapTopUserAgent(BaseModel): + count: int + """The number of requests made with the user agent""" + + user_agent: str + """The user agent that was used""" diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/__init__.py b/tests/api_resources/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cdn/__init__.py b/tests/api_resources/cdn/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cdn/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cdn/cdn_resources/__init__.py b/tests/api_resources/cdn/cdn_resources/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cdn/cdn_resources/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cdn/cdn_resources/test_rules.py b/tests/api_resources/cdn/cdn_resources/test_rules.py new file mode 100644 index 00000000..5fd9a3d7 --- /dev/null +++ b/tests/api_resources/cdn/cdn_resources/test_rules.py @@ -0,0 +1,2131 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn.cdn_resources import ( + CDNResourceRule, + RuleListResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRules: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + rule = client.cdn.cdn_resources.rules.create( + resource_id=0, + name="My first rule", + rule="/folder/images/*.png", + rule_type=0, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + rule = client.cdn.cdn_resources.rules.create( + resource_id=0, + name="My first rule", + rule="/folder/images/*.png", + rule_type=0, + active=True, + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + origin_group=None, + override_origin_protocol="HTTPS", + weight=1, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.rules.with_raw_response.create( + resource_id=0, + name="My first rule", + rule="/folder/images/*.png", + rule_type=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cdn.cdn_resources.rules.with_streaming_response.create( + resource_id=0, + name="My first rule", + rule="/folder/images/*.png", + rule_type=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + rule = client.cdn.cdn_resources.rules.update( + rule_id=0, + resource_id=0, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + rule = client.cdn.cdn_resources.rules.update( + rule_id=0, + resource_id=0, + active=True, + name="My first rule", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + origin_group=None, + override_origin_protocol="HTTPS", + rule="/folder/images/*.png", + rule_type=0, + weight=1, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.rules.with_raw_response.update( + rule_id=0, + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cdn.cdn_resources.rules.with_streaming_response.update( + rule_id=0, + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + rule = client.cdn.cdn_resources.rules.list( + 0, + ) + assert_matches_type(RuleListResponse, rule, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.rules.with_raw_response.list( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert_matches_type(RuleListResponse, rule, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.cdn_resources.rules.with_streaming_response.list( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert_matches_type(RuleListResponse, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + rule = client.cdn.cdn_resources.rules.delete( + rule_id=0, + resource_id=0, + ) + assert rule is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.rules.with_raw_response.delete( + rule_id=0, + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert rule is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cdn.cdn_resources.rules.with_streaming_response.delete( + rule_id=0, + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + rule = client.cdn.cdn_resources.rules.get( + rule_id=0, + resource_id=0, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.rules.with_raw_response.get( + rule_id=0, + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cdn.cdn_resources.rules.with_streaming_response.get( + rule_id=0, + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + rule = client.cdn.cdn_resources.rules.replace( + rule_id=0, + resource_id=0, + rule="/folder/images/*.png", + rule_type=0, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + rule = client.cdn.cdn_resources.rules.replace( + rule_id=0, + resource_id=0, + rule="/folder/images/*.png", + rule_type=0, + active=True, + name="My first rule", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + origin_group=None, + override_origin_protocol="HTTPS", + weight=1, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.rules.with_raw_response.replace( + rule_id=0, + resource_id=0, + rule="/folder/images/*.png", + rule_type=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.cdn.cdn_resources.rules.with_streaming_response.replace( + rule_id=0, + resource_id=0, + rule="/folder/images/*.png", + rule_type=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncRules: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + rule = await async_client.cdn.cdn_resources.rules.create( + resource_id=0, + name="My first rule", + rule="/folder/images/*.png", + rule_type=0, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + rule = await async_client.cdn.cdn_resources.rules.create( + resource_id=0, + name="My first rule", + rule="/folder/images/*.png", + rule_type=0, + active=True, + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + origin_group=None, + override_origin_protocol="HTTPS", + weight=1, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.rules.with_raw_response.create( + resource_id=0, + name="My first rule", + rule="/folder/images/*.png", + rule_type=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.rules.with_streaming_response.create( + resource_id=0, + name="My first rule", + rule="/folder/images/*.png", + rule_type=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + rule = await async_client.cdn.cdn_resources.rules.update( + rule_id=0, + resource_id=0, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + rule = await async_client.cdn.cdn_resources.rules.update( + rule_id=0, + resource_id=0, + active=True, + name="My first rule", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + origin_group=None, + override_origin_protocol="HTTPS", + rule="/folder/images/*.png", + rule_type=0, + weight=1, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.rules.with_raw_response.update( + rule_id=0, + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.rules.with_streaming_response.update( + rule_id=0, + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + rule = await async_client.cdn.cdn_resources.rules.list( + 0, + ) + assert_matches_type(RuleListResponse, rule, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.rules.with_raw_response.list( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert_matches_type(RuleListResponse, rule, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.rules.with_streaming_response.list( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert_matches_type(RuleListResponse, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + rule = await async_client.cdn.cdn_resources.rules.delete( + rule_id=0, + resource_id=0, + ) + assert rule is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.rules.with_raw_response.delete( + rule_id=0, + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert rule is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.rules.with_streaming_response.delete( + rule_id=0, + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + rule = await async_client.cdn.cdn_resources.rules.get( + rule_id=0, + resource_id=0, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.rules.with_raw_response.get( + rule_id=0, + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.rules.with_streaming_response.get( + rule_id=0, + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + rule = await async_client.cdn.cdn_resources.rules.replace( + rule_id=0, + resource_id=0, + rule="/folder/images/*.png", + rule_type=0, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + rule = await async_client.cdn.cdn_resources.rules.replace( + rule_id=0, + resource_id=0, + rule="/folder/images/*.png", + rule_type=0, + active=True, + name="My first rule", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + origin_group=None, + override_origin_protocol="HTTPS", + weight=1, + ) + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.rules.with_raw_response.replace( + rule_id=0, + resource_id=0, + rule="/folder/images/*.png", + rule_type=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.rules.with_streaming_response.replace( + rule_id=0, + resource_id=0, + rule="/folder/images/*.png", + rule_type=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert_matches_type(CDNResourceRule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/cdn_resources/test_shield.py b/tests/api_resources/cdn/cdn_resources/test_shield.py new file mode 100644 index 00000000..dcc9f67c --- /dev/null +++ b/tests/api_resources/cdn/cdn_resources/test_shield.py @@ -0,0 +1,164 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn.cdn_resources import OriginShielding + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestShield: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + shield = client.cdn.cdn_resources.shield.get( + 0, + ) + assert_matches_type(OriginShielding, shield, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.shield.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + shield = response.parse() + assert_matches_type(OriginShielding, shield, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cdn.cdn_resources.shield.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + shield = response.parse() + assert_matches_type(OriginShielding, shield, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + shield = client.cdn.cdn_resources.shield.replace( + resource_id=0, + ) + assert_matches_type(object, shield, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + shield = client.cdn.cdn_resources.shield.replace( + resource_id=0, + shielding_pop=4, + ) + assert_matches_type(object, shield, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.shield.with_raw_response.replace( + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + shield = response.parse() + assert_matches_type(object, shield, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.cdn.cdn_resources.shield.with_streaming_response.replace( + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + shield = response.parse() + assert_matches_type(object, shield, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncShield: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + shield = await async_client.cdn.cdn_resources.shield.get( + 0, + ) + assert_matches_type(OriginShielding, shield, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.shield.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + shield = await response.parse() + assert_matches_type(OriginShielding, shield, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.shield.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + shield = await response.parse() + assert_matches_type(OriginShielding, shield, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + shield = await async_client.cdn.cdn_resources.shield.replace( + resource_id=0, + ) + assert_matches_type(object, shield, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + shield = await async_client.cdn.cdn_resources.shield.replace( + resource_id=0, + shielding_pop=4, + ) + assert_matches_type(object, shield, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.shield.with_raw_response.replace( + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + shield = await response.parse() + assert_matches_type(object, shield, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.shield.with_streaming_response.replace( + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + shield = await response.parse() + assert_matches_type(object, shield, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/logs_uploader/__init__.py b/tests/api_resources/cdn/logs_uploader/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cdn/logs_uploader/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cdn/logs_uploader/test_configs.py b/tests/api_resources/cdn/logs_uploader/test_configs.py new file mode 100644 index 00000000..77fc82eb --- /dev/null +++ b/tests/api_resources/cdn/logs_uploader/test_configs.py @@ -0,0 +1,572 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import LogsUploaderValidation +from gcore.types.cdn.logs_uploader import ( + LogsUploaderConfig, + LogsUploaderConfigList, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestConfigs: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + config = client.cdn.logs_uploader.configs.create( + name="name", + policy=0, + target=0, + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + config = client.cdn.logs_uploader.configs.create( + name="name", + policy=0, + target=0, + enabled=True, + for_all_resources=True, + resources=[0], + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.configs.with_raw_response.create( + name="name", + policy=0, + target=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cdn.logs_uploader.configs.with_streaming_response.create( + name="name", + policy=0, + target=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + config = client.cdn.logs_uploader.configs.update( + id=0, + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + config = client.cdn.logs_uploader.configs.update( + id=0, + enabled=True, + for_all_resources=True, + name="name", + policy=0, + resources=[0], + target=0, + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.configs.with_raw_response.update( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cdn.logs_uploader.configs.with_streaming_response.update( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + config = client.cdn.logs_uploader.configs.list() + assert_matches_type(LogsUploaderConfigList, config, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + config = client.cdn.logs_uploader.configs.list( + resource_ids=[0], + search="search", + ) + assert_matches_type(LogsUploaderConfigList, config, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.configs.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = response.parse() + assert_matches_type(LogsUploaderConfigList, config, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.logs_uploader.configs.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = response.parse() + assert_matches_type(LogsUploaderConfigList, config, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + config = client.cdn.logs_uploader.configs.delete( + 0, + ) + assert config is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.configs.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = response.parse() + assert config is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cdn.logs_uploader.configs.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = response.parse() + assert config is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + config = client.cdn.logs_uploader.configs.get( + 0, + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.configs.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cdn.logs_uploader.configs.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + config = client.cdn.logs_uploader.configs.replace( + id=0, + name="name", + policy=0, + target=0, + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + config = client.cdn.logs_uploader.configs.replace( + id=0, + name="name", + policy=0, + target=0, + enabled=True, + for_all_resources=True, + resources=[0], + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.configs.with_raw_response.replace( + id=0, + name="name", + policy=0, + target=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.cdn.logs_uploader.configs.with_streaming_response.replace( + id=0, + name="name", + policy=0, + target=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_validate(self, client: Gcore) -> None: + config = client.cdn.logs_uploader.configs.validate( + 0, + ) + assert_matches_type(LogsUploaderValidation, config, path=["response"]) + + @parametrize + def test_raw_response_validate(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.configs.with_raw_response.validate( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = response.parse() + assert_matches_type(LogsUploaderValidation, config, path=["response"]) + + @parametrize + def test_streaming_response_validate(self, client: Gcore) -> None: + with client.cdn.logs_uploader.configs.with_streaming_response.validate( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = response.parse() + assert_matches_type(LogsUploaderValidation, config, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncConfigs: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + config = await async_client.cdn.logs_uploader.configs.create( + name="name", + policy=0, + target=0, + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + config = await async_client.cdn.logs_uploader.configs.create( + name="name", + policy=0, + target=0, + enabled=True, + for_all_resources=True, + resources=[0], + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.configs.with_raw_response.create( + name="name", + policy=0, + target=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = await response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.configs.with_streaming_response.create( + name="name", + policy=0, + target=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = await response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + config = await async_client.cdn.logs_uploader.configs.update( + id=0, + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + config = await async_client.cdn.logs_uploader.configs.update( + id=0, + enabled=True, + for_all_resources=True, + name="name", + policy=0, + resources=[0], + target=0, + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.configs.with_raw_response.update( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = await response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.configs.with_streaming_response.update( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = await response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + config = await async_client.cdn.logs_uploader.configs.list() + assert_matches_type(LogsUploaderConfigList, config, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + config = await async_client.cdn.logs_uploader.configs.list( + resource_ids=[0], + search="search", + ) + assert_matches_type(LogsUploaderConfigList, config, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.configs.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = await response.parse() + assert_matches_type(LogsUploaderConfigList, config, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.configs.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = await response.parse() + assert_matches_type(LogsUploaderConfigList, config, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + config = await async_client.cdn.logs_uploader.configs.delete( + 0, + ) + assert config is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.configs.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = await response.parse() + assert config is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.configs.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = await response.parse() + assert config is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + config = await async_client.cdn.logs_uploader.configs.get( + 0, + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.configs.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = await response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.configs.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = await response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + config = await async_client.cdn.logs_uploader.configs.replace( + id=0, + name="name", + policy=0, + target=0, + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + config = await async_client.cdn.logs_uploader.configs.replace( + id=0, + name="name", + policy=0, + target=0, + enabled=True, + for_all_resources=True, + resources=[0], + ) + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.configs.with_raw_response.replace( + id=0, + name="name", + policy=0, + target=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = await response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.configs.with_streaming_response.replace( + id=0, + name="name", + policy=0, + target=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = await response.parse() + assert_matches_type(LogsUploaderConfig, config, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_validate(self, async_client: AsyncGcore) -> None: + config = await async_client.cdn.logs_uploader.configs.validate( + 0, + ) + assert_matches_type(LogsUploaderValidation, config, path=["response"]) + + @parametrize + async def test_raw_response_validate(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.configs.with_raw_response.validate( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + config = await response.parse() + assert_matches_type(LogsUploaderValidation, config, path=["response"]) + + @parametrize + async def test_streaming_response_validate(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.configs.with_streaming_response.validate( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + config = await response.parse() + assert_matches_type(LogsUploaderValidation, config, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/logs_uploader/test_policies.py b/tests/api_resources/cdn/logs_uploader/test_policies.py new file mode 100644 index 00000000..249b03cc --- /dev/null +++ b/tests/api_resources/cdn/logs_uploader/test_policies.py @@ -0,0 +1,584 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn.logs_uploader import ( + LogsUploaderPolicy, + LogsUploaderPolicyList, + PolicyListFieldsResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPolicies: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + policy = client.cdn.logs_uploader.policies.create() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + policy = client.cdn.logs_uploader.policies.create( + date_format="[02/Jan/2006:15:04:05 -0700]", + description="New policy", + escape_special_characters=True, + field_delimiter=",", + field_separator=";", + fields=["remote_addr", "status"], + file_name_template="{{YYYY}}_{{MM}}_{{DD}}_{{HH}}_{{mm}}_{{ss}}_access.log.gz", + format_type="json", + include_empty_logs=True, + include_shield_logs=True, + log_sample_rate=1, + name="Policy", + retry_interval_minutes=32, + rotate_interval_minutes=32, + rotate_threshold_lines=5000, + rotate_threshold_mb=252, + tags={}, + ) + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.policies.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cdn.logs_uploader.policies.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + policy = client.cdn.logs_uploader.policies.update( + id=0, + ) + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + policy = client.cdn.logs_uploader.policies.update( + id=0, + date_format="[02/Jan/2006:15:04:05 -0700]", + description="New policy", + escape_special_characters=True, + field_delimiter=",", + field_separator=";", + fields=["remote_addr", "status"], + file_name_template="{{YYYY}}_{{MM}}_{{DD}}_{{HH}}_{{mm}}_{{ss}}_access.log.gz", + format_type="json", + include_empty_logs=True, + include_shield_logs=True, + log_sample_rate=0.5, + name="Policy", + retry_interval_minutes=32, + rotate_interval_minutes=32, + rotate_threshold_lines=5000, + rotate_threshold_mb=252, + tags={}, + ) + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.policies.with_raw_response.update( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cdn.logs_uploader.policies.with_streaming_response.update( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + policy = client.cdn.logs_uploader.policies.list() + assert_matches_type(LogsUploaderPolicyList, policy, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + policy = client.cdn.logs_uploader.policies.list( + config_ids=[0], + search="search", + ) + assert_matches_type(LogsUploaderPolicyList, policy, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.policies.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(LogsUploaderPolicyList, policy, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.logs_uploader.policies.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(LogsUploaderPolicyList, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + policy = client.cdn.logs_uploader.policies.delete( + 0, + ) + assert policy is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.policies.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert policy is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cdn.logs_uploader.policies.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert policy is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + policy = client.cdn.logs_uploader.policies.get( + 0, + ) + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.policies.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cdn.logs_uploader.policies.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_fields(self, client: Gcore) -> None: + policy = client.cdn.logs_uploader.policies.list_fields() + assert_matches_type(PolicyListFieldsResponse, policy, path=["response"]) + + @parametrize + def test_raw_response_list_fields(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.policies.with_raw_response.list_fields() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(PolicyListFieldsResponse, policy, path=["response"]) + + @parametrize + def test_streaming_response_list_fields(self, client: Gcore) -> None: + with client.cdn.logs_uploader.policies.with_streaming_response.list_fields() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(PolicyListFieldsResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + policy = client.cdn.logs_uploader.policies.replace( + id=0, + ) + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + policy = client.cdn.logs_uploader.policies.replace( + id=0, + date_format="[02/Jan/2006:15:04:05 -0700]", + description="New policy", + escape_special_characters=True, + field_delimiter=",", + field_separator=";", + fields=["remote_addr", "status"], + file_name_template="{{YYYY}}_{{MM}}_{{DD}}_{{HH}}_{{mm}}_{{ss}}_access.log.gz", + format_type="json", + include_empty_logs=True, + include_shield_logs=True, + log_sample_rate=1, + name="Policy", + retry_interval_minutes=32, + rotate_interval_minutes=32, + rotate_threshold_lines=5000, + rotate_threshold_mb=252, + tags={}, + ) + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.policies.with_raw_response.replace( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.cdn.logs_uploader.policies.with_streaming_response.replace( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncPolicies: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + policy = await async_client.cdn.logs_uploader.policies.create() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + policy = await async_client.cdn.logs_uploader.policies.create( + date_format="[02/Jan/2006:15:04:05 -0700]", + description="New policy", + escape_special_characters=True, + field_delimiter=",", + field_separator=";", + fields=["remote_addr", "status"], + file_name_template="{{YYYY}}_{{MM}}_{{DD}}_{{HH}}_{{mm}}_{{ss}}_access.log.gz", + format_type="json", + include_empty_logs=True, + include_shield_logs=True, + log_sample_rate=1, + name="Policy", + retry_interval_minutes=32, + rotate_interval_minutes=32, + rotate_threshold_lines=5000, + rotate_threshold_mb=252, + tags={}, + ) + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.policies.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.policies.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + policy = await async_client.cdn.logs_uploader.policies.update( + id=0, + ) + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + policy = await async_client.cdn.logs_uploader.policies.update( + id=0, + date_format="[02/Jan/2006:15:04:05 -0700]", + description="New policy", + escape_special_characters=True, + field_delimiter=",", + field_separator=";", + fields=["remote_addr", "status"], + file_name_template="{{YYYY}}_{{MM}}_{{DD}}_{{HH}}_{{mm}}_{{ss}}_access.log.gz", + format_type="json", + include_empty_logs=True, + include_shield_logs=True, + log_sample_rate=0.5, + name="Policy", + retry_interval_minutes=32, + rotate_interval_minutes=32, + rotate_threshold_lines=5000, + rotate_threshold_mb=252, + tags={}, + ) + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.policies.with_raw_response.update( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.policies.with_streaming_response.update( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + policy = await async_client.cdn.logs_uploader.policies.list() + assert_matches_type(LogsUploaderPolicyList, policy, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + policy = await async_client.cdn.logs_uploader.policies.list( + config_ids=[0], + search="search", + ) + assert_matches_type(LogsUploaderPolicyList, policy, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.policies.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(LogsUploaderPolicyList, policy, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.policies.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(LogsUploaderPolicyList, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + policy = await async_client.cdn.logs_uploader.policies.delete( + 0, + ) + assert policy is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.policies.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert policy is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.policies.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert policy is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + policy = await async_client.cdn.logs_uploader.policies.get( + 0, + ) + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.policies.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.policies.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_fields(self, async_client: AsyncGcore) -> None: + policy = await async_client.cdn.logs_uploader.policies.list_fields() + assert_matches_type(PolicyListFieldsResponse, policy, path=["response"]) + + @parametrize + async def test_raw_response_list_fields(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.policies.with_raw_response.list_fields() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(PolicyListFieldsResponse, policy, path=["response"]) + + @parametrize + async def test_streaming_response_list_fields(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.policies.with_streaming_response.list_fields() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(PolicyListFieldsResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + policy = await async_client.cdn.logs_uploader.policies.replace( + id=0, + ) + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + policy = await async_client.cdn.logs_uploader.policies.replace( + id=0, + date_format="[02/Jan/2006:15:04:05 -0700]", + description="New policy", + escape_special_characters=True, + field_delimiter=",", + field_separator=";", + fields=["remote_addr", "status"], + file_name_template="{{YYYY}}_{{MM}}_{{DD}}_{{HH}}_{{mm}}_{{ss}}_access.log.gz", + format_type="json", + include_empty_logs=True, + include_shield_logs=True, + log_sample_rate=1, + name="Policy", + retry_interval_minutes=32, + rotate_interval_minutes=32, + rotate_threshold_lines=5000, + rotate_threshold_mb=252, + tags={}, + ) + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.policies.with_raw_response.replace( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.policies.with_streaming_response.replace( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(LogsUploaderPolicy, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/logs_uploader/test_targets.py b/tests/api_resources/cdn/logs_uploader/test_targets.py new file mode 100644 index 00000000..3cea5248 --- /dev/null +++ b/tests/api_resources/cdn/logs_uploader/test_targets.py @@ -0,0 +1,668 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import LogsUploaderValidation +from gcore.types.cdn.logs_uploader import ( + LogsUploaderTarget, + LogsUploaderTargetList, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTargets: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + target = client.cdn.logs_uploader.targets.create( + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + }, + storage_type="s3_gcore", + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + target = client.cdn.logs_uploader.targets.create( + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + "directory": "directory", + "use_path_style": True, + }, + storage_type="s3_gcore", + description="description", + name="name", + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.targets.with_raw_response.create( + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + }, + storage_type="s3_gcore", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cdn.logs_uploader.targets.with_streaming_response.create( + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + }, + storage_type="s3_gcore", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + target = client.cdn.logs_uploader.targets.update( + id=0, + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + target = client.cdn.logs_uploader.targets.update( + id=0, + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + "directory": "directory", + "use_path_style": True, + }, + description="description", + name="name", + storage_type="s3_gcore", + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.targets.with_raw_response.update( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cdn.logs_uploader.targets.with_streaming_response.update( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + target = client.cdn.logs_uploader.targets.list() + assert_matches_type(LogsUploaderTargetList, target, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + target = client.cdn.logs_uploader.targets.list( + config_ids=[0], + search="search", + ) + assert_matches_type(LogsUploaderTargetList, target, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.targets.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = response.parse() + assert_matches_type(LogsUploaderTargetList, target, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.logs_uploader.targets.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = response.parse() + assert_matches_type(LogsUploaderTargetList, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + target = client.cdn.logs_uploader.targets.delete( + 0, + ) + assert target is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.targets.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = response.parse() + assert target is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cdn.logs_uploader.targets.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = response.parse() + assert target is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + target = client.cdn.logs_uploader.targets.get( + 0, + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.targets.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cdn.logs_uploader.targets.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + target = client.cdn.logs_uploader.targets.replace( + id=0, + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + }, + storage_type="s3_gcore", + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + target = client.cdn.logs_uploader.targets.replace( + id=0, + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + "directory": "directory", + "use_path_style": True, + }, + storage_type="s3_gcore", + description="description", + name="name", + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.targets.with_raw_response.replace( + id=0, + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + }, + storage_type="s3_gcore", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.cdn.logs_uploader.targets.with_streaming_response.replace( + id=0, + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + }, + storage_type="s3_gcore", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_validate(self, client: Gcore) -> None: + target = client.cdn.logs_uploader.targets.validate( + 0, + ) + assert_matches_type(LogsUploaderValidation, target, path=["response"]) + + @parametrize + def test_raw_response_validate(self, client: Gcore) -> None: + response = client.cdn.logs_uploader.targets.with_raw_response.validate( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = response.parse() + assert_matches_type(LogsUploaderValidation, target, path=["response"]) + + @parametrize + def test_streaming_response_validate(self, client: Gcore) -> None: + with client.cdn.logs_uploader.targets.with_streaming_response.validate( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = response.parse() + assert_matches_type(LogsUploaderValidation, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncTargets: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + target = await async_client.cdn.logs_uploader.targets.create( + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + }, + storage_type="s3_gcore", + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + target = await async_client.cdn.logs_uploader.targets.create( + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + "directory": "directory", + "use_path_style": True, + }, + storage_type="s3_gcore", + description="description", + name="name", + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.targets.with_raw_response.create( + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + }, + storage_type="s3_gcore", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = await response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.targets.with_streaming_response.create( + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + }, + storage_type="s3_gcore", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = await response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + target = await async_client.cdn.logs_uploader.targets.update( + id=0, + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + target = await async_client.cdn.logs_uploader.targets.update( + id=0, + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + "directory": "directory", + "use_path_style": True, + }, + description="description", + name="name", + storage_type="s3_gcore", + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.targets.with_raw_response.update( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = await response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.targets.with_streaming_response.update( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = await response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + target = await async_client.cdn.logs_uploader.targets.list() + assert_matches_type(LogsUploaderTargetList, target, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + target = await async_client.cdn.logs_uploader.targets.list( + config_ids=[0], + search="search", + ) + assert_matches_type(LogsUploaderTargetList, target, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.targets.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = await response.parse() + assert_matches_type(LogsUploaderTargetList, target, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.targets.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = await response.parse() + assert_matches_type(LogsUploaderTargetList, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + target = await async_client.cdn.logs_uploader.targets.delete( + 0, + ) + assert target is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.targets.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = await response.parse() + assert target is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.targets.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = await response.parse() + assert target is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + target = await async_client.cdn.logs_uploader.targets.get( + 0, + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.targets.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = await response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.targets.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = await response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + target = await async_client.cdn.logs_uploader.targets.replace( + id=0, + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + }, + storage_type="s3_gcore", + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + target = await async_client.cdn.logs_uploader.targets.replace( + id=0, + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + "directory": "directory", + "use_path_style": True, + }, + storage_type="s3_gcore", + description="description", + name="name", + ) + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.targets.with_raw_response.replace( + id=0, + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + }, + storage_type="s3_gcore", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = await response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.targets.with_streaming_response.replace( + id=0, + config={ + "access_key_id": "access_key_id", + "bucket_name": "bucket_name", + "endpoint": "endpoint", + "region": "region", + "secret_access_key": "secret_access_key", + }, + storage_type="s3_gcore", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = await response.parse() + assert_matches_type(LogsUploaderTarget, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_validate(self, async_client: AsyncGcore) -> None: + target = await async_client.cdn.logs_uploader.targets.validate( + 0, + ) + assert_matches_type(LogsUploaderValidation, target, path=["response"]) + + @parametrize + async def test_raw_response_validate(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs_uploader.targets.with_raw_response.validate( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = await response.parse() + assert_matches_type(LogsUploaderValidation, target, path=["response"]) + + @parametrize + async def test_streaming_response_validate(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs_uploader.targets.with_streaming_response.validate( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = await response.parse() + assert_matches_type(LogsUploaderValidation, target, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/test_audit_logs.py b/tests/api_resources/cdn/test_audit_logs.py new file mode 100644 index 00000000..ae9cea06 --- /dev/null +++ b/tests/api_resources/cdn/test_audit_logs.py @@ -0,0 +1,171 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import CDNAuditLogEntry +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAuditLogs: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + audit_log = client.cdn.audit_logs.list() + assert_matches_type(SyncOffsetPage[CDNAuditLogEntry], audit_log, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + audit_log = client.cdn.audit_logs.list( + client_id=0, + limit=0, + max_requested_at="max_requested_at", + method="method", + min_requested_at="min_requested_at", + offset=0, + path="path", + remote_ip_address="remote_ip_address", + status_code=0, + token_id=0, + user_id=0, + ) + assert_matches_type(SyncOffsetPage[CDNAuditLogEntry], audit_log, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.audit_logs.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + audit_log = response.parse() + assert_matches_type(SyncOffsetPage[CDNAuditLogEntry], audit_log, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.audit_logs.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + audit_log = response.parse() + assert_matches_type(SyncOffsetPage[CDNAuditLogEntry], audit_log, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + audit_log = client.cdn.audit_logs.get( + 0, + ) + assert_matches_type(CDNAuditLogEntry, audit_log, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cdn.audit_logs.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + audit_log = response.parse() + assert_matches_type(CDNAuditLogEntry, audit_log, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cdn.audit_logs.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + audit_log = response.parse() + assert_matches_type(CDNAuditLogEntry, audit_log, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAuditLogs: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + audit_log = await async_client.cdn.audit_logs.list() + assert_matches_type(AsyncOffsetPage[CDNAuditLogEntry], audit_log, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + audit_log = await async_client.cdn.audit_logs.list( + client_id=0, + limit=0, + max_requested_at="max_requested_at", + method="method", + min_requested_at="min_requested_at", + offset=0, + path="path", + remote_ip_address="remote_ip_address", + status_code=0, + token_id=0, + user_id=0, + ) + assert_matches_type(AsyncOffsetPage[CDNAuditLogEntry], audit_log, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.audit_logs.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + audit_log = await response.parse() + assert_matches_type(AsyncOffsetPage[CDNAuditLogEntry], audit_log, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.audit_logs.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + audit_log = await response.parse() + assert_matches_type(AsyncOffsetPage[CDNAuditLogEntry], audit_log, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + audit_log = await async_client.cdn.audit_logs.get( + 0, + ) + assert_matches_type(CDNAuditLogEntry, audit_log, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.audit_logs.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + audit_log = await response.parse() + assert_matches_type(CDNAuditLogEntry, audit_log, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.audit_logs.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + audit_log = await response.parse() + assert_matches_type(CDNAuditLogEntry, audit_log, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/test_cdn_resources.py b/tests/api_resources/cdn/test_cdn_resources.py new file mode 100644 index 00000000..097c60c0 --- /dev/null +++ b/tests/api_resources/cdn/test_cdn_resources.py @@ -0,0 +1,2635 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import ( + CDNResource, + CDNResourceList, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCDNResources: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.create( + cname="cdn.site.com", + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.create( + cname="cdn.site.com", + active=True, + description="My resource", + name="Resource for images", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "http3_enabled": { + "enabled": True, + "value": True, + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "tls_versions": { + "enabled": True, + "value": ["SSLv3", "TLSv1.3"], + }, + "use_default_le_chain": { + "enabled": True, + "value": True, + }, + "use_dns01_le_challenge": { + "enabled": True, + "value": True, + }, + "use_rsa_le_cert": { + "enabled": True, + "value": True, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + origin="example.com", + origin_group=132, + origin_protocol="HTTPS", + primary_resource=None, + proxy_ssl_ca=None, + proxy_ssl_data=None, + proxy_ssl_enabled=False, + secondary_hostnames=["first.example.com", "second.example.com"], + ssl_data=192, + ssl_enabled=False, + waap_api_domain_enabled=True, + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.with_raw_response.create( + cname="cdn.site.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cdn.cdn_resources.with_streaming_response.create( + cname="cdn.site.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="unexpected prism python test failures") + @parametrize + def test_method_update(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.update( + resource_id=0, + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @pytest.mark.skip(reason="unexpected prism python test failures") + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.update( + resource_id=0, + active=True, + description="My resource", + name="Resource for images", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "http3_enabled": { + "enabled": True, + "value": True, + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "tls_versions": { + "enabled": True, + "value": ["SSLv3", "TLSv1.3"], + }, + "use_default_le_chain": { + "enabled": True, + "value": True, + }, + "use_dns01_le_challenge": { + "enabled": True, + "value": True, + }, + "use_rsa_le_cert": { + "enabled": True, + "value": True, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + origin_group=132, + origin_protocol="HTTPS", + proxy_ssl_ca=None, + proxy_ssl_data=None, + proxy_ssl_enabled=False, + secondary_hostnames=["first.example.com", "second.example.com"], + ssl_data=192, + ssl_enabled=False, + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @pytest.mark.skip(reason="unexpected prism python test failures") + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.with_raw_response.update( + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @pytest.mark.skip(reason="unexpected prism python test failures") + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cdn.cdn_resources.with_streaming_response.update( + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.list() + assert_matches_type(CDNResourceList, cdn_resource, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.list( + cname="cname", + deleted=True, + enabled=True, + max_created="max_created", + min_created="min_created", + origin_group=0, + rules="rules", + secondary_hostnames="secondaryHostnames", + shield_dc="shield_dc", + shielded=True, + ssl_data=0, + ssl_data_in=0, + ssl_enabled=True, + status="active", + suspend=True, + vp_enabled=True, + ) + assert_matches_type(CDNResourceList, cdn_resource, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = response.parse() + assert_matches_type(CDNResourceList, cdn_resource, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.cdn_resources.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = response.parse() + assert_matches_type(CDNResourceList, cdn_resource, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.delete( + 0, + ) + assert cdn_resource is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = response.parse() + assert cdn_resource is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cdn.cdn_resources.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = response.parse() + assert cdn_resource is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.get( + 0, + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cdn.cdn_resources.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_prefetch(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.prefetch( + resource_id=0, + paths=["/test.jpg", "test1.jpg"], + ) + assert cdn_resource is None + + @parametrize + def test_raw_response_prefetch(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.with_raw_response.prefetch( + resource_id=0, + paths=["/test.jpg", "test1.jpg"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = response.parse() + assert cdn_resource is None + + @parametrize + def test_streaming_response_prefetch(self, client: Gcore) -> None: + with client.cdn.cdn_resources.with_streaming_response.prefetch( + resource_id=0, + paths=["/test.jpg", "test1.jpg"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = response.parse() + assert cdn_resource is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_prevalidate_ssl_le_certificate(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.prevalidate_ssl_le_certificate( + 0, + ) + assert cdn_resource is None + + @parametrize + def test_raw_response_prevalidate_ssl_le_certificate(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.with_raw_response.prevalidate_ssl_le_certificate( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = response.parse() + assert cdn_resource is None + + @parametrize + def test_streaming_response_prevalidate_ssl_le_certificate(self, client: Gcore) -> None: + with client.cdn.cdn_resources.with_streaming_response.prevalidate_ssl_le_certificate( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = response.parse() + assert cdn_resource is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_purge_overload_1(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.purge( + resource_id=0, + ) + assert cdn_resource is None + + @parametrize + def test_method_purge_with_all_params_overload_1(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.purge( + resource_id=0, + urls=["/some-url.jpg", "/img/example.jpg"], + ) + assert cdn_resource is None + + @parametrize + def test_raw_response_purge_overload_1(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.with_raw_response.purge( + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = response.parse() + assert cdn_resource is None + + @parametrize + def test_streaming_response_purge_overload_1(self, client: Gcore) -> None: + with client.cdn.cdn_resources.with_streaming_response.purge( + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = response.parse() + assert cdn_resource is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_purge_overload_2(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.purge( + resource_id=0, + ) + assert cdn_resource is None + + @parametrize + def test_method_purge_with_all_params_overload_2(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.purge( + resource_id=0, + paths=["/images/*", "/videos/*"], + ) + assert cdn_resource is None + + @parametrize + def test_raw_response_purge_overload_2(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.with_raw_response.purge( + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = response.parse() + assert cdn_resource is None + + @parametrize + def test_streaming_response_purge_overload_2(self, client: Gcore) -> None: + with client.cdn.cdn_resources.with_streaming_response.purge( + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = response.parse() + assert cdn_resource is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_purge_overload_3(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.purge( + resource_id=0, + ) + assert cdn_resource is None + + @parametrize + def test_method_purge_with_all_params_overload_3(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.purge( + resource_id=0, + paths=["string"], + ) + assert cdn_resource is None + + @parametrize + def test_raw_response_purge_overload_3(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.with_raw_response.purge( + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = response.parse() + assert cdn_resource is None + + @parametrize + def test_streaming_response_purge_overload_3(self, client: Gcore) -> None: + with client.cdn.cdn_resources.with_streaming_response.purge( + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = response.parse() + assert cdn_resource is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.replace( + resource_id=0, + origin_group=132, + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + cdn_resource = client.cdn.cdn_resources.replace( + resource_id=0, + origin_group=132, + active=True, + description="My resource", + name="Resource for images", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "http3_enabled": { + "enabled": True, + "value": True, + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "tls_versions": { + "enabled": True, + "value": ["SSLv3", "TLSv1.3"], + }, + "use_default_le_chain": { + "enabled": True, + "value": True, + }, + "use_dns01_le_challenge": { + "enabled": True, + "value": True, + }, + "use_rsa_le_cert": { + "enabled": True, + "value": True, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + origin_protocol="HTTPS", + proxy_ssl_ca=None, + proxy_ssl_data=None, + proxy_ssl_enabled=False, + secondary_hostnames=["first.example.com", "second.example.com"], + ssl_data=192, + ssl_enabled=False, + waap_api_domain_enabled=True, + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.cdn.cdn_resources.with_raw_response.replace( + resource_id=0, + origin_group=132, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.cdn.cdn_resources.with_streaming_response.replace( + resource_id=0, + origin_group=132, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncCDNResources: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.create( + cname="cdn.site.com", + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.create( + cname="cdn.site.com", + active=True, + description="My resource", + name="Resource for images", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "http3_enabled": { + "enabled": True, + "value": True, + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "tls_versions": { + "enabled": True, + "value": ["SSLv3", "TLSv1.3"], + }, + "use_default_le_chain": { + "enabled": True, + "value": True, + }, + "use_dns01_le_challenge": { + "enabled": True, + "value": True, + }, + "use_rsa_le_cert": { + "enabled": True, + "value": True, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + origin="example.com", + origin_group=132, + origin_protocol="HTTPS", + primary_resource=None, + proxy_ssl_ca=None, + proxy_ssl_data=None, + proxy_ssl_enabled=False, + secondary_hostnames=["first.example.com", "second.example.com"], + ssl_data=192, + ssl_enabled=False, + waap_api_domain_enabled=True, + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.with_raw_response.create( + cname="cdn.site.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = await response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.with_streaming_response.create( + cname="cdn.site.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = await response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="unexpected prism python test failures") + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.update( + resource_id=0, + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @pytest.mark.skip(reason="unexpected prism python test failures") + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.update( + resource_id=0, + active=True, + description="My resource", + name="Resource for images", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "http3_enabled": { + "enabled": True, + "value": True, + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "tls_versions": { + "enabled": True, + "value": ["SSLv3", "TLSv1.3"], + }, + "use_default_le_chain": { + "enabled": True, + "value": True, + }, + "use_dns01_le_challenge": { + "enabled": True, + "value": True, + }, + "use_rsa_le_cert": { + "enabled": True, + "value": True, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + origin_group=132, + origin_protocol="HTTPS", + proxy_ssl_ca=None, + proxy_ssl_data=None, + proxy_ssl_enabled=False, + secondary_hostnames=["first.example.com", "second.example.com"], + ssl_data=192, + ssl_enabled=False, + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @pytest.mark.skip(reason="unexpected prism python test failures") + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.with_raw_response.update( + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = await response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @pytest.mark.skip(reason="unexpected prism python test failures") + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.with_streaming_response.update( + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = await response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.list() + assert_matches_type(CDNResourceList, cdn_resource, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.list( + cname="cname", + deleted=True, + enabled=True, + max_created="max_created", + min_created="min_created", + origin_group=0, + rules="rules", + secondary_hostnames="secondaryHostnames", + shield_dc="shield_dc", + shielded=True, + ssl_data=0, + ssl_data_in=0, + ssl_enabled=True, + status="active", + suspend=True, + vp_enabled=True, + ) + assert_matches_type(CDNResourceList, cdn_resource, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = await response.parse() + assert_matches_type(CDNResourceList, cdn_resource, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = await response.parse() + assert_matches_type(CDNResourceList, cdn_resource, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.delete( + 0, + ) + assert cdn_resource is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = await response.parse() + assert cdn_resource is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = await response.parse() + assert cdn_resource is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.get( + 0, + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = await response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = await response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_prefetch(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.prefetch( + resource_id=0, + paths=["/test.jpg", "test1.jpg"], + ) + assert cdn_resource is None + + @parametrize + async def test_raw_response_prefetch(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.with_raw_response.prefetch( + resource_id=0, + paths=["/test.jpg", "test1.jpg"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = await response.parse() + assert cdn_resource is None + + @parametrize + async def test_streaming_response_prefetch(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.with_streaming_response.prefetch( + resource_id=0, + paths=["/test.jpg", "test1.jpg"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = await response.parse() + assert cdn_resource is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_prevalidate_ssl_le_certificate(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.prevalidate_ssl_le_certificate( + 0, + ) + assert cdn_resource is None + + @parametrize + async def test_raw_response_prevalidate_ssl_le_certificate(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.with_raw_response.prevalidate_ssl_le_certificate( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = await response.parse() + assert cdn_resource is None + + @parametrize + async def test_streaming_response_prevalidate_ssl_le_certificate(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.with_streaming_response.prevalidate_ssl_le_certificate( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = await response.parse() + assert cdn_resource is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_purge_overload_1(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.purge( + resource_id=0, + ) + assert cdn_resource is None + + @parametrize + async def test_method_purge_with_all_params_overload_1(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.purge( + resource_id=0, + urls=["/some-url.jpg", "/img/example.jpg"], + ) + assert cdn_resource is None + + @parametrize + async def test_raw_response_purge_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.with_raw_response.purge( + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = await response.parse() + assert cdn_resource is None + + @parametrize + async def test_streaming_response_purge_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.with_streaming_response.purge( + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = await response.parse() + assert cdn_resource is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_purge_overload_2(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.purge( + resource_id=0, + ) + assert cdn_resource is None + + @parametrize + async def test_method_purge_with_all_params_overload_2(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.purge( + resource_id=0, + paths=["/images/*", "/videos/*"], + ) + assert cdn_resource is None + + @parametrize + async def test_raw_response_purge_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.with_raw_response.purge( + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = await response.parse() + assert cdn_resource is None + + @parametrize + async def test_streaming_response_purge_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.with_streaming_response.purge( + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = await response.parse() + assert cdn_resource is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_purge_overload_3(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.purge( + resource_id=0, + ) + assert cdn_resource is None + + @parametrize + async def test_method_purge_with_all_params_overload_3(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.purge( + resource_id=0, + paths=["string"], + ) + assert cdn_resource is None + + @parametrize + async def test_raw_response_purge_overload_3(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.with_raw_response.purge( + resource_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = await response.parse() + assert cdn_resource is None + + @parametrize + async def test_streaming_response_purge_overload_3(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.with_streaming_response.purge( + resource_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = await response.parse() + assert cdn_resource is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.replace( + resource_id=0, + origin_group=132, + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + cdn_resource = await async_client.cdn.cdn_resources.replace( + resource_id=0, + origin_group=132, + active=True, + description="My resource", + name="Resource for images", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "http3_enabled": { + "enabled": True, + "value": True, + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "tls_versions": { + "enabled": True, + "value": ["SSLv3", "TLSv1.3"], + }, + "use_default_le_chain": { + "enabled": True, + "value": True, + }, + "use_dns01_le_challenge": { + "enabled": True, + "value": True, + }, + "use_rsa_le_cert": { + "enabled": True, + "value": True, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + origin_protocol="HTTPS", + proxy_ssl_ca=None, + proxy_ssl_data=None, + proxy_ssl_enabled=False, + secondary_hostnames=["first.example.com", "second.example.com"], + ssl_data=192, + ssl_enabled=False, + waap_api_domain_enabled=True, + ) + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.cdn_resources.with_raw_response.replace( + resource_id=0, + origin_group=132, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn_resource = await response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.cdn_resources.with_streaming_response.replace( + resource_id=0, + origin_group=132, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn_resource = await response.parse() + assert_matches_type(CDNResource, cdn_resource, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/test_certificates.py b/tests/api_resources/cdn/test_certificates.py new file mode 100644 index 00000000..da6d3aad --- /dev/null +++ b/tests/api_resources/cdn/test_certificates.py @@ -0,0 +1,686 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import ( + SslDetail, + SslDetailList, + SslRequestStatus, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCertificates: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create_overload_1(self, client: Gcore) -> None: + certificate = client.cdn.certificates.create( + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + ) + assert certificate is None + + @parametrize + def test_method_create_with_all_params_overload_1(self, client: Gcore) -> None: + certificate = client.cdn.certificates.create( + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + validate_root_ca=True, + ) + assert certificate is None + + @parametrize + def test_raw_response_create_overload_1(self, client: Gcore) -> None: + response = client.cdn.certificates.with_raw_response.create( + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert certificate is None + + @parametrize + def test_streaming_response_create_overload_1(self, client: Gcore) -> None: + with client.cdn.certificates.with_streaming_response.create( + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert certificate is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_2(self, client: Gcore) -> None: + certificate = client.cdn.certificates.create( + automated=True, + name="New Let's Encrypt certificate", + ) + assert certificate is None + + @parametrize + def test_raw_response_create_overload_2(self, client: Gcore) -> None: + response = client.cdn.certificates.with_raw_response.create( + automated=True, + name="New Let's Encrypt certificate", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert certificate is None + + @parametrize + def test_streaming_response_create_overload_2(self, client: Gcore) -> None: + with client.cdn.certificates.with_streaming_response.create( + automated=True, + name="New Let's Encrypt certificate", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert certificate is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + certificate = client.cdn.certificates.list() + assert_matches_type(SslDetailList, certificate, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + certificate = client.cdn.certificates.list( + automated=True, + resource_id=0, + validity_not_after_lte="validity_not_after_lte", + ) + assert_matches_type(SslDetailList, certificate, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.certificates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(SslDetailList, certificate, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.certificates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(SslDetailList, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + certificate = client.cdn.certificates.delete( + 0, + ) + assert certificate is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cdn.certificates.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert certificate is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cdn.certificates.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert certificate is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_force_retry(self, client: Gcore) -> None: + certificate = client.cdn.certificates.force_retry( + 0, + ) + assert certificate is None + + @parametrize + def test_raw_response_force_retry(self, client: Gcore) -> None: + response = client.cdn.certificates.with_raw_response.force_retry( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert certificate is None + + @parametrize + def test_streaming_response_force_retry(self, client: Gcore) -> None: + with client.cdn.certificates.with_streaming_response.force_retry( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert certificate is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + certificate = client.cdn.certificates.get( + 0, + ) + assert_matches_type(SslDetail, certificate, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cdn.certificates.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(SslDetail, certificate, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cdn.certificates.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(SslDetail, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_status(self, client: Gcore) -> None: + certificate = client.cdn.certificates.get_status( + cert_id=0, + ) + assert_matches_type(SslRequestStatus, certificate, path=["response"]) + + @parametrize + def test_method_get_status_with_all_params(self, client: Gcore) -> None: + certificate = client.cdn.certificates.get_status( + cert_id=0, + exclude=["string"], + ) + assert_matches_type(SslRequestStatus, certificate, path=["response"]) + + @parametrize + def test_raw_response_get_status(self, client: Gcore) -> None: + response = client.cdn.certificates.with_raw_response.get_status( + cert_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(SslRequestStatus, certificate, path=["response"]) + + @parametrize + def test_streaming_response_get_status(self, client: Gcore) -> None: + with client.cdn.certificates.with_streaming_response.get_status( + cert_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(SslRequestStatus, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_renew(self, client: Gcore) -> None: + certificate = client.cdn.certificates.renew( + 0, + ) + assert certificate is None + + @parametrize + def test_raw_response_renew(self, client: Gcore) -> None: + response = client.cdn.certificates.with_raw_response.renew( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert certificate is None + + @parametrize + def test_streaming_response_renew(self, client: Gcore) -> None: + with client.cdn.certificates.with_streaming_response.renew( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert certificate is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + certificate = client.cdn.certificates.replace( + ssl_id=0, + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + ) + assert_matches_type(SslDetail, certificate, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + certificate = client.cdn.certificates.replace( + ssl_id=0, + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + validate_root_ca=True, + ) + assert_matches_type(SslDetail, certificate, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.cdn.certificates.with_raw_response.replace( + ssl_id=0, + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = response.parse() + assert_matches_type(SslDetail, certificate, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.cdn.certificates.with_streaming_response.replace( + ssl_id=0, + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = response.parse() + assert_matches_type(SslDetail, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncCertificates: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create_overload_1(self, async_client: AsyncGcore) -> None: + certificate = await async_client.cdn.certificates.create( + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + ) + assert certificate is None + + @parametrize + async def test_method_create_with_all_params_overload_1(self, async_client: AsyncGcore) -> None: + certificate = await async_client.cdn.certificates.create( + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + validate_root_ca=True, + ) + assert certificate is None + + @parametrize + async def test_raw_response_create_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.certificates.with_raw_response.create( + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = await response.parse() + assert certificate is None + + @parametrize + async def test_streaming_response_create_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.certificates.with_streaming_response.create( + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert certificate is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_2(self, async_client: AsyncGcore) -> None: + certificate = await async_client.cdn.certificates.create( + automated=True, + name="New Let's Encrypt certificate", + ) + assert certificate is None + + @parametrize + async def test_raw_response_create_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.certificates.with_raw_response.create( + automated=True, + name="New Let's Encrypt certificate", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = await response.parse() + assert certificate is None + + @parametrize + async def test_streaming_response_create_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.certificates.with_streaming_response.create( + automated=True, + name="New Let's Encrypt certificate", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert certificate is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + certificate = await async_client.cdn.certificates.list() + assert_matches_type(SslDetailList, certificate, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + certificate = await async_client.cdn.certificates.list( + automated=True, + resource_id=0, + validity_not_after_lte="validity_not_after_lte", + ) + assert_matches_type(SslDetailList, certificate, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.certificates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = await response.parse() + assert_matches_type(SslDetailList, certificate, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.certificates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(SslDetailList, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + certificate = await async_client.cdn.certificates.delete( + 0, + ) + assert certificate is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.certificates.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = await response.parse() + assert certificate is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.certificates.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert certificate is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_force_retry(self, async_client: AsyncGcore) -> None: + certificate = await async_client.cdn.certificates.force_retry( + 0, + ) + assert certificate is None + + @parametrize + async def test_raw_response_force_retry(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.certificates.with_raw_response.force_retry( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = await response.parse() + assert certificate is None + + @parametrize + async def test_streaming_response_force_retry(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.certificates.with_streaming_response.force_retry( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert certificate is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + certificate = await async_client.cdn.certificates.get( + 0, + ) + assert_matches_type(SslDetail, certificate, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.certificates.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = await response.parse() + assert_matches_type(SslDetail, certificate, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.certificates.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(SslDetail, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_status(self, async_client: AsyncGcore) -> None: + certificate = await async_client.cdn.certificates.get_status( + cert_id=0, + ) + assert_matches_type(SslRequestStatus, certificate, path=["response"]) + + @parametrize + async def test_method_get_status_with_all_params(self, async_client: AsyncGcore) -> None: + certificate = await async_client.cdn.certificates.get_status( + cert_id=0, + exclude=["string"], + ) + assert_matches_type(SslRequestStatus, certificate, path=["response"]) + + @parametrize + async def test_raw_response_get_status(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.certificates.with_raw_response.get_status( + cert_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = await response.parse() + assert_matches_type(SslRequestStatus, certificate, path=["response"]) + + @parametrize + async def test_streaming_response_get_status(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.certificates.with_streaming_response.get_status( + cert_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(SslRequestStatus, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_renew(self, async_client: AsyncGcore) -> None: + certificate = await async_client.cdn.certificates.renew( + 0, + ) + assert certificate is None + + @parametrize + async def test_raw_response_renew(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.certificates.with_raw_response.renew( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = await response.parse() + assert certificate is None + + @parametrize + async def test_streaming_response_renew(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.certificates.with_streaming_response.renew( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert certificate is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + certificate = await async_client.cdn.certificates.replace( + ssl_id=0, + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + ) + assert_matches_type(SslDetail, certificate, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + certificate = await async_client.cdn.certificates.replace( + ssl_id=0, + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + validate_root_ca=True, + ) + assert_matches_type(SslDetail, certificate, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.certificates.with_raw_response.replace( + ssl_id=0, + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + certificate = await response.parse() + assert_matches_type(SslDetail, certificate, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.certificates.with_streaming_response.replace( + ssl_id=0, + name="New certificate", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIFWzCCBEOgAwIBAgISBK6qoNitg//89H/YJamujpWlMA0GCSqGSIb3DQEBCwUA\nMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\nExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODExMTMxMjQwMDJaFw0x\nOTAyMTExMjQwMDJaMBwxGjAYBgNVBAMTEWNkbjIudG50LWNsdWIuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaHExDEXNSf6ELS0WUR7qq8gs9cc\nxx99sM2zs3Jld0twPmuldkVNe5xte/Hj03r4SesfOBczR7pn+t60YujPvUQDN8lx\nWYpvRuetOneyf4gNPatwzR/W1GWGlahet1xPVYGrttqL4gCJeShIXvU4aCyzW941\nPt0wCs+bg9u+59fXFkigWrWJPkwbR7bJ14XTStYynMbYLfCg+VPeGWj3d8wOhQcf\nAD86o8TLTbVfK2BDXwS5S8Dgf5u8g+WvmVHYDIkYKCxcLj0jP61Y7uHoFbSg41oN\nA9yPOa+0cYxA7U702V2WjxbfIeATYtNLZvH17lk+DYlQl8q3MLwguqZdgwIDAQAB\niIqI2xquGONtHFDOKJvy1O2qYTVRtNRVZqhc1ol+mw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\nSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\nGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\nq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\nSMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\nKOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n-----END CERTIFICATE-----\n", + ssl_private_key="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZcNCZiNNHfX2O\ndZpf12mv2rAZwqGZBAdpox0wntEPK3JciQ7ZRloLJeHuCNIJs9MidnH7Xk8zveju\nmab6HmfIzvMJAAm88OYWMFQRiYe1ggJEHMe7yYPQbtXwTqWDYdWmjPPma3Ujqqmb\nhmVX2rsYILD7cUjS+e0Ucfqx3QODQj/aujTt1rS0gFhJ0soY5m+C6VimPCx4Bjyw\n5rhtskJDRrfXxrIhVXOvSPFRyxDSfjt3win8vjhhZ3oFPWgrl9lVhn0zaB5hjDsd\n-----END PRIVATE KEY-----\n", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + certificate = await response.parse() + assert_matches_type(SslDetail, certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/test_ip_ranges.py b/tests/api_resources/cdn/test_ip_ranges.py new file mode 100644 index 00000000..b4967cd6 --- /dev/null +++ b/tests/api_resources/cdn/test_ip_ranges.py @@ -0,0 +1,156 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import PublicIPList, PublicNetworkList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestIPRanges: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + ip_range = client.cdn.ip_ranges.list() + assert_matches_type(PublicNetworkList, ip_range, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + ip_range = client.cdn.ip_ranges.list( + format="json", + accept="application/json", + ) + assert_matches_type(PublicNetworkList, ip_range, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.ip_ranges.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_range = response.parse() + assert_matches_type(PublicNetworkList, ip_range, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.ip_ranges.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_range = response.parse() + assert_matches_type(PublicNetworkList, ip_range, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_ips(self, client: Gcore) -> None: + ip_range = client.cdn.ip_ranges.list_ips() + assert_matches_type(PublicIPList, ip_range, path=["response"]) + + @parametrize + def test_method_list_ips_with_all_params(self, client: Gcore) -> None: + ip_range = client.cdn.ip_ranges.list_ips( + format="json", + accept="application/json", + ) + assert_matches_type(PublicIPList, ip_range, path=["response"]) + + @parametrize + def test_raw_response_list_ips(self, client: Gcore) -> None: + response = client.cdn.ip_ranges.with_raw_response.list_ips() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_range = response.parse() + assert_matches_type(PublicIPList, ip_range, path=["response"]) + + @parametrize + def test_streaming_response_list_ips(self, client: Gcore) -> None: + with client.cdn.ip_ranges.with_streaming_response.list_ips() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_range = response.parse() + assert_matches_type(PublicIPList, ip_range, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncIPRanges: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + ip_range = await async_client.cdn.ip_ranges.list() + assert_matches_type(PublicNetworkList, ip_range, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + ip_range = await async_client.cdn.ip_ranges.list( + format="json", + accept="application/json", + ) + assert_matches_type(PublicNetworkList, ip_range, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.ip_ranges.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_range = await response.parse() + assert_matches_type(PublicNetworkList, ip_range, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.ip_ranges.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_range = await response.parse() + assert_matches_type(PublicNetworkList, ip_range, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_ips(self, async_client: AsyncGcore) -> None: + ip_range = await async_client.cdn.ip_ranges.list_ips() + assert_matches_type(PublicIPList, ip_range, path=["response"]) + + @parametrize + async def test_method_list_ips_with_all_params(self, async_client: AsyncGcore) -> None: + ip_range = await async_client.cdn.ip_ranges.list_ips( + format="json", + accept="application/json", + ) + assert_matches_type(PublicIPList, ip_range, path=["response"]) + + @parametrize + async def test_raw_response_list_ips(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.ip_ranges.with_raw_response.list_ips() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_range = await response.parse() + assert_matches_type(PublicIPList, ip_range, path=["response"]) + + @parametrize + async def test_streaming_response_list_ips(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.ip_ranges.with_streaming_response.list_ips() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_range = await response.parse() + assert_matches_type(PublicIPList, ip_range, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/test_logs.py b/tests/api_resources/cdn/test_logs.py new file mode 100644 index 00000000..f72d4e71 --- /dev/null +++ b/tests/api_resources/cdn/test_logs.py @@ -0,0 +1,437 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import httpx +import pytest +from respx import MockRouter + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._response import ( + BinaryAPIResponse, + AsyncBinaryAPIResponse, + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, +) +from gcore.pagination import SyncOffsetPageCDNLogs, AsyncOffsetPageCDNLogs +from gcore.types.cdn.cdn_log_entry import Data + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestLogs: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + log = client.cdn.logs.list( + from_="from", + to="to", + ) + assert_matches_type(SyncOffsetPageCDNLogs[Data], log, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + log = client.cdn.logs.list( + from_="from", + to="to", + cache_status_eq="cache_status__eq", + cache_status_in="cache_status__in", + cache_status_ne="cache_status__ne", + cache_status_not_in="cache_status__not_in", + client_ip_eq="client_ip__eq", + client_ip_in="client_ip__in", + client_ip_ne="client_ip__ne", + client_ip_not_in="client_ip__not_in", + cname_contains="cname__contains", + cname_eq="cname__eq", + cname_in="cname__in", + cname_ne="cname__ne", + cname_not_in="cname__not_in", + datacenter_eq="datacenter__eq", + datacenter_in="datacenter__in", + datacenter_ne="datacenter__ne", + datacenter_not_in="datacenter__not_in", + fields="fields", + limit=1, + method_eq="method__eq", + method_in="method__in", + method_ne="method__ne", + method_not_in="method__not_in", + offset=0, + ordering="ordering", + resource_id_eq=0, + resource_id_gt=0, + resource_id_gte=0, + resource_id_in="resource_id__in", + resource_id_lt=0, + resource_id_lte=0, + resource_id_ne=0, + resource_id_not_in="resource_id__not_in", + size_eq=0, + size_gt=0, + size_gte=0, + size_in="size__in", + size_lt=0, + size_lte=0, + size_ne=0, + size_not_in="size__not_in", + status_eq=0, + status_gt=0, + status_gte=0, + status_in="status__in", + status_lt=0, + status_lte=0, + status_ne=0, + status_not_in="status__not_in", + ) + assert_matches_type(SyncOffsetPageCDNLogs[Data], log, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.logs.with_raw_response.list( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + log = response.parse() + assert_matches_type(SyncOffsetPageCDNLogs[Data], log, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.logs.with_streaming_response.list( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + log = response.parse() + assert_matches_type(SyncOffsetPageCDNLogs[Data], log, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_download(self, client: Gcore, respx_mock: MockRouter) -> None: + respx_mock.get("/cdn/advanced/v1/logs/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + log = client.cdn.logs.download( + format="format", + from_="from", + to="to", + ) + assert log.is_closed + assert log.json() == {"foo": "bar"} + assert cast(Any, log.is_closed) is True + assert isinstance(log, BinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_download_with_all_params(self, client: Gcore, respx_mock: MockRouter) -> None: + respx_mock.get("/cdn/advanced/v1/logs/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + log = client.cdn.logs.download( + format="format", + from_="from", + to="to", + cache_status_eq="cache_status__eq", + cache_status_in="cache_status__in", + cache_status_ne="cache_status__ne", + cache_status_not_in="cache_status__not_in", + client_ip_eq="client_ip__eq", + client_ip_in="client_ip__in", + client_ip_ne="client_ip__ne", + client_ip_not_in="client_ip__not_in", + cname_contains="cname__contains", + cname_eq="cname__eq", + cname_in="cname__in", + cname_ne="cname__ne", + cname_not_in="cname__not_in", + datacenter_eq="datacenter__eq", + datacenter_in="datacenter__in", + datacenter_ne="datacenter__ne", + datacenter_not_in="datacenter__not_in", + fields="fields", + limit=10000, + method_eq="method__eq", + method_in="method__in", + method_ne="method__ne", + method_not_in="method__not_in", + offset=0, + resource_id_eq=0, + resource_id_gt=0, + resource_id_gte=0, + resource_id_in="resource_id__in", + resource_id_lt=0, + resource_id_lte=0, + resource_id_ne=0, + resource_id_not_in="resource_id__not_in", + size_eq=0, + size_gt=0, + size_gte=0, + size_in="size__in", + size_lt=0, + size_lte=0, + size_ne=0, + size_not_in="size__not_in", + sort="sort", + status_eq=0, + status_gt=0, + status_gte=0, + status_in="status__in", + status_lt=0, + status_lte=0, + status_ne=0, + status_not_in="status__not_in", + ) + assert log.is_closed + assert log.json() == {"foo": "bar"} + assert cast(Any, log.is_closed) is True + assert isinstance(log, BinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_raw_response_download(self, client: Gcore, respx_mock: MockRouter) -> None: + respx_mock.get("/cdn/advanced/v1/logs/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + log = client.cdn.logs.with_raw_response.download( + format="format", + from_="from", + to="to", + ) + + assert log.is_closed is True + assert log.http_request.headers.get("X-Stainless-Lang") == "python" + assert log.json() == {"foo": "bar"} + assert isinstance(log, BinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_streaming_response_download(self, client: Gcore, respx_mock: MockRouter) -> None: + respx_mock.get("/cdn/advanced/v1/logs/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + with client.cdn.logs.with_streaming_response.download( + format="format", + from_="from", + to="to", + ) as log: + assert not log.is_closed + assert log.http_request.headers.get("X-Stainless-Lang") == "python" + + assert log.json() == {"foo": "bar"} + assert cast(Any, log.is_closed) is True + assert isinstance(log, StreamedBinaryAPIResponse) + + assert cast(Any, log.is_closed) is True + + +class TestAsyncLogs: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + log = await async_client.cdn.logs.list( + from_="from", + to="to", + ) + assert_matches_type(AsyncOffsetPageCDNLogs[Data], log, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + log = await async_client.cdn.logs.list( + from_="from", + to="to", + cache_status_eq="cache_status__eq", + cache_status_in="cache_status__in", + cache_status_ne="cache_status__ne", + cache_status_not_in="cache_status__not_in", + client_ip_eq="client_ip__eq", + client_ip_in="client_ip__in", + client_ip_ne="client_ip__ne", + client_ip_not_in="client_ip__not_in", + cname_contains="cname__contains", + cname_eq="cname__eq", + cname_in="cname__in", + cname_ne="cname__ne", + cname_not_in="cname__not_in", + datacenter_eq="datacenter__eq", + datacenter_in="datacenter__in", + datacenter_ne="datacenter__ne", + datacenter_not_in="datacenter__not_in", + fields="fields", + limit=1, + method_eq="method__eq", + method_in="method__in", + method_ne="method__ne", + method_not_in="method__not_in", + offset=0, + ordering="ordering", + resource_id_eq=0, + resource_id_gt=0, + resource_id_gte=0, + resource_id_in="resource_id__in", + resource_id_lt=0, + resource_id_lte=0, + resource_id_ne=0, + resource_id_not_in="resource_id__not_in", + size_eq=0, + size_gt=0, + size_gte=0, + size_in="size__in", + size_lt=0, + size_lte=0, + size_ne=0, + size_not_in="size__not_in", + status_eq=0, + status_gt=0, + status_gte=0, + status_in="status__in", + status_lt=0, + status_lte=0, + status_ne=0, + status_not_in="status__not_in", + ) + assert_matches_type(AsyncOffsetPageCDNLogs[Data], log, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.logs.with_raw_response.list( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + log = await response.parse() + assert_matches_type(AsyncOffsetPageCDNLogs[Data], log, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.logs.with_streaming_response.list( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + log = await response.parse() + assert_matches_type(AsyncOffsetPageCDNLogs[Data], log, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_download(self, async_client: AsyncGcore, respx_mock: MockRouter) -> None: + respx_mock.get("/cdn/advanced/v1/logs/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + log = await async_client.cdn.logs.download( + format="format", + from_="from", + to="to", + ) + assert log.is_closed + assert await log.json() == {"foo": "bar"} + assert cast(Any, log.is_closed) is True + assert isinstance(log, AsyncBinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_download_with_all_params(self, async_client: AsyncGcore, respx_mock: MockRouter) -> None: + respx_mock.get("/cdn/advanced/v1/logs/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + log = await async_client.cdn.logs.download( + format="format", + from_="from", + to="to", + cache_status_eq="cache_status__eq", + cache_status_in="cache_status__in", + cache_status_ne="cache_status__ne", + cache_status_not_in="cache_status__not_in", + client_ip_eq="client_ip__eq", + client_ip_in="client_ip__in", + client_ip_ne="client_ip__ne", + client_ip_not_in="client_ip__not_in", + cname_contains="cname__contains", + cname_eq="cname__eq", + cname_in="cname__in", + cname_ne="cname__ne", + cname_not_in="cname__not_in", + datacenter_eq="datacenter__eq", + datacenter_in="datacenter__in", + datacenter_ne="datacenter__ne", + datacenter_not_in="datacenter__not_in", + fields="fields", + limit=10000, + method_eq="method__eq", + method_in="method__in", + method_ne="method__ne", + method_not_in="method__not_in", + offset=0, + resource_id_eq=0, + resource_id_gt=0, + resource_id_gte=0, + resource_id_in="resource_id__in", + resource_id_lt=0, + resource_id_lte=0, + resource_id_ne=0, + resource_id_not_in="resource_id__not_in", + size_eq=0, + size_gt=0, + size_gte=0, + size_in="size__in", + size_lt=0, + size_lte=0, + size_ne=0, + size_not_in="size__not_in", + sort="sort", + status_eq=0, + status_gt=0, + status_gte=0, + status_in="status__in", + status_lt=0, + status_lte=0, + status_ne=0, + status_not_in="status__not_in", + ) + assert log.is_closed + assert await log.json() == {"foo": "bar"} + assert cast(Any, log.is_closed) is True + assert isinstance(log, AsyncBinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_raw_response_download(self, async_client: AsyncGcore, respx_mock: MockRouter) -> None: + respx_mock.get("/cdn/advanced/v1/logs/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + log = await async_client.cdn.logs.with_raw_response.download( + format="format", + from_="from", + to="to", + ) + + assert log.is_closed is True + assert log.http_request.headers.get("X-Stainless-Lang") == "python" + assert await log.json() == {"foo": "bar"} + assert isinstance(log, AsyncBinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_streaming_response_download(self, async_client: AsyncGcore, respx_mock: MockRouter) -> None: + respx_mock.get("/cdn/advanced/v1/logs/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + async with async_client.cdn.logs.with_streaming_response.download( + format="format", + from_="from", + to="to", + ) as log: + assert not log.is_closed + assert log.http_request.headers.get("X-Stainless-Lang") == "python" + + assert await log.json() == {"foo": "bar"} + assert cast(Any, log.is_closed) is True + assert isinstance(log, AsyncStreamedBinaryAPIResponse) + + assert cast(Any, log.is_closed) is True diff --git a/tests/api_resources/cdn/test_metrics.py b/tests/api_resources/cdn/test_metrics.py new file mode 100644 index 00000000..40040587 --- /dev/null +++ b/tests/api_resources/cdn/test_metrics.py @@ -0,0 +1,134 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import CDNMetrics + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMetrics: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + metric = client.cdn.metrics.list( + from_="2021-06-14T00:00:00Z", + metrics=["edge_status_2xx", "edge_status_3xx", "edge_status_4xx", "edge_status_5xx"], + to="2021-06-15T00:00:00Z", + ) + assert_matches_type(CDNMetrics, metric, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + metric = client.cdn.metrics.list( + from_="2021-06-14T00:00:00Z", + metrics=["edge_status_2xx", "edge_status_3xx", "edge_status_4xx", "edge_status_5xx"], + to="2021-06-15T00:00:00Z", + filter_by=[ + { + "field": "resource", + "op": "eq", + "values": [1234], + } + ], + granularity="P1D", + group_by=["cname"], + ) + assert_matches_type(CDNMetrics, metric, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.metrics.with_raw_response.list( + from_="2021-06-14T00:00:00Z", + metrics=["edge_status_2xx", "edge_status_3xx", "edge_status_4xx", "edge_status_5xx"], + to="2021-06-15T00:00:00Z", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + metric = response.parse() + assert_matches_type(CDNMetrics, metric, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.metrics.with_streaming_response.list( + from_="2021-06-14T00:00:00Z", + metrics=["edge_status_2xx", "edge_status_3xx", "edge_status_4xx", "edge_status_5xx"], + to="2021-06-15T00:00:00Z", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + metric = response.parse() + assert_matches_type(CDNMetrics, metric, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncMetrics: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + metric = await async_client.cdn.metrics.list( + from_="2021-06-14T00:00:00Z", + metrics=["edge_status_2xx", "edge_status_3xx", "edge_status_4xx", "edge_status_5xx"], + to="2021-06-15T00:00:00Z", + ) + assert_matches_type(CDNMetrics, metric, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + metric = await async_client.cdn.metrics.list( + from_="2021-06-14T00:00:00Z", + metrics=["edge_status_2xx", "edge_status_3xx", "edge_status_4xx", "edge_status_5xx"], + to="2021-06-15T00:00:00Z", + filter_by=[ + { + "field": "resource", + "op": "eq", + "values": [1234], + } + ], + granularity="P1D", + group_by=["cname"], + ) + assert_matches_type(CDNMetrics, metric, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.metrics.with_raw_response.list( + from_="2021-06-14T00:00:00Z", + metrics=["edge_status_2xx", "edge_status_3xx", "edge_status_4xx", "edge_status_5xx"], + to="2021-06-15T00:00:00Z", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + metric = await response.parse() + assert_matches_type(CDNMetrics, metric, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.metrics.with_streaming_response.list( + from_="2021-06-14T00:00:00Z", + metrics=["edge_status_2xx", "edge_status_3xx", "edge_status_4xx", "edge_status_5xx"], + to="2021-06-15T00:00:00Z", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + metric = await response.parse() + assert_matches_type(CDNMetrics, metric, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/test_network_capacity.py b/tests/api_resources/cdn/test_network_capacity.py new file mode 100644 index 00000000..39fc89da --- /dev/null +++ b/tests/api_resources/cdn/test_network_capacity.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import NetworkCapacity + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestNetworkCapacity: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + network_capacity = client.cdn.network_capacity.list() + assert_matches_type(NetworkCapacity, network_capacity, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.network_capacity.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_capacity = response.parse() + assert_matches_type(NetworkCapacity, network_capacity, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.network_capacity.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_capacity = response.parse() + assert_matches_type(NetworkCapacity, network_capacity, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncNetworkCapacity: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + network_capacity = await async_client.cdn.network_capacity.list() + assert_matches_type(NetworkCapacity, network_capacity, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.network_capacity.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_capacity = await response.parse() + assert_matches_type(NetworkCapacity, network_capacity, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.network_capacity.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_capacity = await response.parse() + assert_matches_type(NetworkCapacity, network_capacity, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/test_origin_groups.py b/tests/api_resources/cdn/test_origin_groups.py new file mode 100644 index 00000000..43dc567c --- /dev/null +++ b/tests/api_resources/cdn/test_origin_groups.py @@ -0,0 +1,971 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import ( + OriginGroups, + OriginGroupsList, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestOriginGroups: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create_overload_1(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.create( + name="YourOriginGroup", + sources=[{}, {}], + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_1(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.create( + name="YourOriginGroup", + sources=[ + { + "backup": False, + "enabled": True, + "source": "yourwebsite.com", + }, + { + "backup": True, + "enabled": True, + "source": "1.2.3.4:5500", + }, + ], + auth_type="none", + proxy_next_upstream=["error", "timeout", "invalid_header", "http_500", "http_502", "http_503", "http_504"], + use_next=True, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_raw_response_create_overload_1(self, client: Gcore) -> None: + response = client.cdn.origin_groups.with_raw_response.create( + name="YourOriginGroup", + sources=[{}, {}], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_1(self, client: Gcore) -> None: + with client.cdn.origin_groups.with_streaming_response.create( + name="YourOriginGroup", + sources=[{}, {}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_2(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.create( + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_2(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.create( + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + "s3_region": "us-east-2", + "s3_storage_hostname": "s3_storage_hostname", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + proxy_next_upstream=["error", "timeout", "invalid_header", "http_500", "http_502", "http_503", "http_504"], + use_next=True, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_raw_response_create_overload_2(self, client: Gcore) -> None: + response = client.cdn.origin_groups.with_raw_response.create( + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_2(self, client: Gcore) -> None: + with client.cdn.origin_groups.with_streaming_response.create( + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update_overload_1(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.update( + origin_group_id=0, + name="YourOriginGroup", + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_method_update_with_all_params_overload_1(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.update( + origin_group_id=0, + name="YourOriginGroup", + auth_type="none", + path="", + proxy_next_upstream=["error", "timeout", "invalid_header", "http_500", "http_502", "http_503", "http_504"], + sources=[ + { + "backup": False, + "enabled": True, + "source": "yourdomain.com", + } + ], + use_next=True, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_raw_response_update_overload_1(self, client: Gcore) -> None: + response = client.cdn.origin_groups.with_raw_response.update( + origin_group_id=0, + name="YourOriginGroup", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_streaming_response_update_overload_1(self, client: Gcore) -> None: + with client.cdn.origin_groups.with_streaming_response.update( + origin_group_id=0, + name="YourOriginGroup", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update_overload_2(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.update( + origin_group_id=0, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_method_update_with_all_params_overload_2(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.update( + origin_group_id=0, + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + "s3_region": "us-east-2", + "s3_storage_hostname": "s3_storage_hostname", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + path="", + proxy_next_upstream=["error", "timeout", "invalid_header", "http_500", "http_502", "http_503", "http_504"], + use_next=True, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_raw_response_update_overload_2(self, client: Gcore) -> None: + response = client.cdn.origin_groups.with_raw_response.update( + origin_group_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_streaming_response_update_overload_2(self, client: Gcore) -> None: + with client.cdn.origin_groups.with_streaming_response.update( + origin_group_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.list() + assert_matches_type(OriginGroupsList, origin_group, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.list( + has_related_resources=True, + name="name", + sources="sources", + ) + assert_matches_type(OriginGroupsList, origin_group, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.origin_groups.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = response.parse() + assert_matches_type(OriginGroupsList, origin_group, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.origin_groups.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = response.parse() + assert_matches_type(OriginGroupsList, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.delete( + 0, + ) + assert origin_group is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cdn.origin_groups.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = response.parse() + assert origin_group is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cdn.origin_groups.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = response.parse() + assert origin_group is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.get( + 0, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cdn.origin_groups.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cdn.origin_groups.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace_overload_1(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.replace( + origin_group_id=0, + auth_type="none", + name="YourOriginGroup", + path="", + sources=[{}], + use_next=True, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_method_replace_with_all_params_overload_1(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.replace( + origin_group_id=0, + auth_type="none", + name="YourOriginGroup", + path="", + sources=[ + { + "backup": False, + "enabled": True, + "source": "yourdomain.com", + } + ], + use_next=True, + proxy_next_upstream=["error", "timeout", "invalid_header", "http_500", "http_502", "http_503", "http_504"], + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_raw_response_replace_overload_1(self, client: Gcore) -> None: + response = client.cdn.origin_groups.with_raw_response.replace( + origin_group_id=0, + auth_type="none", + name="YourOriginGroup", + path="", + sources=[{}], + use_next=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_streaming_response_replace_overload_1(self, client: Gcore) -> None: + with client.cdn.origin_groups.with_streaming_response.replace( + origin_group_id=0, + auth_type="none", + name="YourOriginGroup", + path="", + sources=[{}], + use_next=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace_overload_2(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.replace( + origin_group_id=0, + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + path="", + use_next=True, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_method_replace_with_all_params_overload_2(self, client: Gcore) -> None: + origin_group = client.cdn.origin_groups.replace( + origin_group_id=0, + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + "s3_region": "us-east-2", + "s3_storage_hostname": "s3_storage_hostname", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + path="", + use_next=True, + proxy_next_upstream=["error", "timeout", "invalid_header", "http_500", "http_502", "http_503", "http_504"], + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_raw_response_replace_overload_2(self, client: Gcore) -> None: + response = client.cdn.origin_groups.with_raw_response.replace( + origin_group_id=0, + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + path="", + use_next=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + def test_streaming_response_replace_overload_2(self, client: Gcore) -> None: + with client.cdn.origin_groups.with_streaming_response.replace( + origin_group_id=0, + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + path="", + use_next=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncOriginGroups: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create_overload_1(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.create( + name="YourOriginGroup", + sources=[{}, {}], + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_1(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.create( + name="YourOriginGroup", + sources=[ + { + "backup": False, + "enabled": True, + "source": "yourwebsite.com", + }, + { + "backup": True, + "enabled": True, + "source": "1.2.3.4:5500", + }, + ], + auth_type="none", + proxy_next_upstream=["error", "timeout", "invalid_header", "http_500", "http_502", "http_503", "http_504"], + use_next=True, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.origin_groups.with_raw_response.create( + name="YourOriginGroup", + sources=[{}, {}], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.origin_groups.with_streaming_response.create( + name="YourOriginGroup", + sources=[{}, {}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_2(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.create( + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_2(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.create( + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + "s3_region": "us-east-2", + "s3_storage_hostname": "s3_storage_hostname", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + proxy_next_upstream=["error", "timeout", "invalid_header", "http_500", "http_502", "http_503", "http_504"], + use_next=True, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.origin_groups.with_raw_response.create( + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.origin_groups.with_streaming_response.create( + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update_overload_1(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.update( + origin_group_id=0, + name="YourOriginGroup", + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_method_update_with_all_params_overload_1(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.update( + origin_group_id=0, + name="YourOriginGroup", + auth_type="none", + path="", + proxy_next_upstream=["error", "timeout", "invalid_header", "http_500", "http_502", "http_503", "http_504"], + sources=[ + { + "backup": False, + "enabled": True, + "source": "yourdomain.com", + } + ], + use_next=True, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_raw_response_update_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.origin_groups.with_raw_response.update( + origin_group_id=0, + name="YourOriginGroup", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_streaming_response_update_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.origin_groups.with_streaming_response.update( + origin_group_id=0, + name="YourOriginGroup", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update_overload_2(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.update( + origin_group_id=0, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_method_update_with_all_params_overload_2(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.update( + origin_group_id=0, + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + "s3_region": "us-east-2", + "s3_storage_hostname": "s3_storage_hostname", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + path="", + proxy_next_upstream=["error", "timeout", "invalid_header", "http_500", "http_502", "http_503", "http_504"], + use_next=True, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_raw_response_update_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.origin_groups.with_raw_response.update( + origin_group_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_streaming_response_update_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.origin_groups.with_streaming_response.update( + origin_group_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.list() + assert_matches_type(OriginGroupsList, origin_group, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.list( + has_related_resources=True, + name="name", + sources="sources", + ) + assert_matches_type(OriginGroupsList, origin_group, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.origin_groups.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = await response.parse() + assert_matches_type(OriginGroupsList, origin_group, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.origin_groups.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = await response.parse() + assert_matches_type(OriginGroupsList, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.delete( + 0, + ) + assert origin_group is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.origin_groups.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = await response.parse() + assert origin_group is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.origin_groups.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = await response.parse() + assert origin_group is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.get( + 0, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.origin_groups.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.origin_groups.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace_overload_1(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.replace( + origin_group_id=0, + auth_type="none", + name="YourOriginGroup", + path="", + sources=[{}], + use_next=True, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params_overload_1(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.replace( + origin_group_id=0, + auth_type="none", + name="YourOriginGroup", + path="", + sources=[ + { + "backup": False, + "enabled": True, + "source": "yourdomain.com", + } + ], + use_next=True, + proxy_next_upstream=["error", "timeout", "invalid_header", "http_500", "http_502", "http_503", "http_504"], + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_raw_response_replace_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.origin_groups.with_raw_response.replace( + origin_group_id=0, + auth_type="none", + name="YourOriginGroup", + path="", + sources=[{}], + use_next=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_streaming_response_replace_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.origin_groups.with_streaming_response.replace( + origin_group_id=0, + auth_type="none", + name="YourOriginGroup", + path="", + sources=[{}], + use_next=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace_overload_2(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.replace( + origin_group_id=0, + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + path="", + use_next=True, + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params_overload_2(self, async_client: AsyncGcore) -> None: + origin_group = await async_client.cdn.origin_groups.replace( + origin_group_id=0, + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + "s3_region": "us-east-2", + "s3_storage_hostname": "s3_storage_hostname", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + path="", + use_next=True, + proxy_next_upstream=["error", "timeout", "invalid_header", "http_500", "http_502", "http_503", "http_504"], + ) + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_raw_response_replace_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.origin_groups.with_raw_response.replace( + origin_group_id=0, + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + path="", + use_next=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + @parametrize + async def test_streaming_response_replace_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.origin_groups.with_streaming_response.replace( + origin_group_id=0, + auth={ + "s3_access_key_id": "EXAMPLEFODNN7EXAMPLE", + "s3_bucket_name": "bucket_name", + "s3_secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_type": "amazon", + }, + auth_type="awsSignatureV4", + name="YourOriginGroup", + path="", + use_next=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + origin_group = await response.parse() + assert_matches_type(OriginGroups, origin_group, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/test_rule_templates.py b/tests/api_resources/cdn/test_rule_templates.py new file mode 100644 index 00000000..e7d8cb23 --- /dev/null +++ b/tests/api_resources/cdn/test_rule_templates.py @@ -0,0 +1,2065 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import ( + RuleTemplate, + RuleTemplateList, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRuleTemplates: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + rule_template = client.cdn.rule_templates.create( + rule="/folder/images/*.png", + rule_type=0, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + rule_template = client.cdn.rule_templates.create( + rule="/folder/images/*.png", + rule_type=0, + name="All images template", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + override_origin_protocol="HTTPS", + weight=1, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cdn.rule_templates.with_raw_response.create( + rule="/folder/images/*.png", + rule_type=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule_template = response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cdn.rule_templates.with_streaming_response.create( + rule="/folder/images/*.png", + rule_type=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule_template = response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + rule_template = client.cdn.rule_templates.update( + rule_template_id=0, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + rule_template = client.cdn.rule_templates.update( + rule_template_id=0, + name="All images template", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + override_origin_protocol="HTTPS", + rule="/folder/images/*.png", + rule_type=0, + weight=1, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cdn.rule_templates.with_raw_response.update( + rule_template_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule_template = response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cdn.rule_templates.with_streaming_response.update( + rule_template_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule_template = response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + rule_template = client.cdn.rule_templates.list() + assert_matches_type(RuleTemplateList, rule_template, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.rule_templates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule_template = response.parse() + assert_matches_type(RuleTemplateList, rule_template, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.rule_templates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule_template = response.parse() + assert_matches_type(RuleTemplateList, rule_template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + rule_template = client.cdn.rule_templates.delete( + 0, + ) + assert rule_template is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cdn.rule_templates.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule_template = response.parse() + assert rule_template is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cdn.rule_templates.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule_template = response.parse() + assert rule_template is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + rule_template = client.cdn.rule_templates.get( + 0, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cdn.rule_templates.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule_template = response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cdn.rule_templates.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule_template = response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + rule_template = client.cdn.rule_templates.replace( + rule_template_id=0, + rule="/folder/images/*.png", + rule_type=0, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + rule_template = client.cdn.rule_templates.replace( + rule_template_id=0, + rule="/folder/images/*.png", + rule_type=0, + name="All images template", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + override_origin_protocol="HTTPS", + weight=1, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.cdn.rule_templates.with_raw_response.replace( + rule_template_id=0, + rule="/folder/images/*.png", + rule_type=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule_template = response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.cdn.rule_templates.with_streaming_response.replace( + rule_template_id=0, + rule="/folder/images/*.png", + rule_type=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule_template = response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncRuleTemplates: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + rule_template = await async_client.cdn.rule_templates.create( + rule="/folder/images/*.png", + rule_type=0, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + rule_template = await async_client.cdn.rule_templates.create( + rule="/folder/images/*.png", + rule_type=0, + name="All images template", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + override_origin_protocol="HTTPS", + weight=1, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.rule_templates.with_raw_response.create( + rule="/folder/images/*.png", + rule_type=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule_template = await response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.rule_templates.with_streaming_response.create( + rule="/folder/images/*.png", + rule_type=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule_template = await response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + rule_template = await async_client.cdn.rule_templates.update( + rule_template_id=0, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + rule_template = await async_client.cdn.rule_templates.update( + rule_template_id=0, + name="All images template", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + override_origin_protocol="HTTPS", + rule="/folder/images/*.png", + rule_type=0, + weight=1, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.rule_templates.with_raw_response.update( + rule_template_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule_template = await response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.rule_templates.with_streaming_response.update( + rule_template_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule_template = await response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + rule_template = await async_client.cdn.rule_templates.list() + assert_matches_type(RuleTemplateList, rule_template, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.rule_templates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule_template = await response.parse() + assert_matches_type(RuleTemplateList, rule_template, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.rule_templates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule_template = await response.parse() + assert_matches_type(RuleTemplateList, rule_template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + rule_template = await async_client.cdn.rule_templates.delete( + 0, + ) + assert rule_template is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.rule_templates.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule_template = await response.parse() + assert rule_template is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.rule_templates.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule_template = await response.parse() + assert rule_template is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + rule_template = await async_client.cdn.rule_templates.get( + 0, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.rule_templates.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule_template = await response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.rule_templates.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule_template = await response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + rule_template = await async_client.cdn.rule_templates.replace( + rule_template_id=0, + rule="/folder/images/*.png", + rule_type=0, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + rule_template = await async_client.cdn.rule_templates.replace( + rule_template_id=0, + rule="/folder/images/*.png", + rule_type=0, + name="All images template", + options={ + "allowed_http_methods": { + "enabled": True, + "value": ["GET", "POST"], + }, + "bot_protection": { + "bot_challenge": {"enabled": True}, + "enabled": True, + }, + "brotli_compression": { + "enabled": True, + "value": ["text/html", "text/plain"], + }, + "browser_cache_settings": { + "enabled": True, + "value": "3600s", + }, + "cache_http_headers": { + "enabled": False, + "value": [ + "vary", + "content-length", + "last-modified", + "connection", + "accept-ranges", + "content-type", + "content-encoding", + "etag", + "cache-control", + "expires", + "keep-alive", + "server", + ], + }, + "cors": { + "enabled": True, + "value": ["domain.com", "domain2.com"], + "always": True, + }, + "country_acl": { + "enabled": True, + "excepted_values": ["GB", "DE"], + "policy_type": "allow", + }, + "disable_cache": { + "enabled": True, + "value": False, + }, + "disable_proxy_force_ranges": { + "enabled": True, + "value": True, + }, + "edge_cache_settings": { + "enabled": True, + "custom_values": {"100": "43200s"}, + "default": "321669910225", + "value": "43200s", + }, + "fastedge": { + "enabled": True, + "on_request_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_request_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_body": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + "on_response_headers": { + "app_id": "1001", + "enabled": True, + "execute_on_edge": True, + "execute_on_shield": False, + "interrupt_on_error": True, + }, + }, + "fetch_compressed": { + "enabled": True, + "value": False, + }, + "follow_origin_redirect": { + "codes": [302, 308], + "enabled": True, + }, + "force_return": { + "body": "http://example.com/redirect_address", + "code": 301, + "enabled": True, + "time_interval": { + "end_time": "20:00", + "start_time": "09:00", + "time_zone": "CET", + }, + }, + "forward_host_header": { + "enabled": False, + "value": False, + }, + "gzip_on": { + "enabled": True, + "value": True, + }, + "host_header": { + "enabled": True, + "value": "host.com", + }, + "ignore_cookie": { + "enabled": True, + "value": True, + }, + "ignore_query_string": { + "enabled": True, + "value": False, + }, + "image_stack": { + "enabled": True, + "avif_enabled": True, + "png_lossless": True, + "quality": 80, + "webp_enabled": False, + }, + "ip_address_acl": { + "enabled": True, + "excepted_values": ["192.168.1.100/32"], + "policy_type": "deny", + }, + "limit_bandwidth": { + "enabled": True, + "limit_type": "static", + "buffer": 200, + "speed": 100, + }, + "proxy_cache_key": { + "enabled": True, + "value": "$scheme$uri", + }, + "proxy_cache_methods_set": { + "enabled": True, + "value": False, + }, + "proxy_connect_timeout": { + "enabled": True, + "value": "4s", + }, + "proxy_read_timeout": { + "enabled": True, + "value": "10s", + }, + "query_params_blacklist": { + "enabled": True, + "value": ["some", "blacklisted", "query"], + }, + "query_params_whitelist": { + "enabled": True, + "value": ["some", "whitelisted", "query"], + }, + "query_string_forwarding": { + "enabled": True, + "forward_from_file_types": ["m3u8", "mpd"], + "forward_to_file_types": ["ts", "mp4"], + "forward_except_keys": ["debug_info"], + "forward_only_keys": ["auth_token", "session_id"], + }, + "redirect_http_to_https": { + "enabled": True, + "value": True, + }, + "redirect_https_to_http": { + "enabled": False, + "value": True, + }, + "referrer_acl": { + "enabled": True, + "excepted_values": ["example.com", "*.example.net"], + "policy_type": "deny", + }, + "request_limiter": { + "enabled": True, + "rate": 5, + "rate_unit": "r/s", + }, + "response_headers_hiding_policy": { + "enabled": True, + "excepted": ["my-header"], + "mode": "hide", + }, + "rewrite": { + "body": "/(.*) /additional_path/$1", + "enabled": True, + "flag": "break", + }, + "secure_key": { + "enabled": True, + "key": "secretkey", + "type": 2, + }, + "slice": { + "enabled": True, + "value": True, + }, + "sni": { + "custom_hostname": "custom.example.com", + "enabled": True, + "sni_type": "custom", + }, + "stale": { + "enabled": True, + "value": ["http_404", "http_500"], + }, + "static_response_headers": { + "enabled": True, + "value": [ + { + "name": "X-Example", + "value": ["Value_1"], + "always": True, + }, + { + "name": "X-Example-Multiple", + "value": ["Value_1", "Value_2", "Value_3"], + "always": False, + }, + ], + }, + "static_headers": { + "enabled": True, + "value": { + "X-Example": "Value_1", + "X-Example-Multiple": ["Value_2", "Value_3"], + }, + }, + "static_request_headers": { + "enabled": True, + "value": { + "Header-One": "Value 1", + "Header-Two": "Value 2", + }, + }, + "user_agent_acl": { + "enabled": True, + "excepted_values": ["UserAgent Value", "~*.*bot.*", ""], + "policy_type": "allow", + }, + "waap": { + "enabled": True, + "value": True, + }, + "websockets": { + "enabled": True, + "value": True, + }, + }, + override_origin_protocol="HTTPS", + weight=1, + ) + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.rule_templates.with_raw_response.replace( + rule_template_id=0, + rule="/folder/images/*.png", + rule_type=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule_template = await response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.rule_templates.with_streaming_response.replace( + rule_template_id=0, + rule="/folder/images/*.png", + rule_type=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule_template = await response.parse() + assert_matches_type(RuleTemplate, rule_template, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/test_shields.py b/tests/api_resources/cdn/test_shields.py new file mode 100644 index 00000000..0600aa49 --- /dev/null +++ b/tests/api_resources/cdn/test_shields.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import ShieldListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestShields: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + shield = client.cdn.shields.list() + assert_matches_type(ShieldListResponse, shield, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.shields.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + shield = response.parse() + assert_matches_type(ShieldListResponse, shield, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.shields.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + shield = response.parse() + assert_matches_type(ShieldListResponse, shield, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncShields: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + shield = await async_client.cdn.shields.list() + assert_matches_type(ShieldListResponse, shield, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.shields.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + shield = await response.parse() + assert_matches_type(ShieldListResponse, shield, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.shields.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + shield = await response.parse() + assert_matches_type(ShieldListResponse, shield, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/test_statistics.py b/tests/api_resources/cdn/test_statistics.py new file mode 100644 index 00000000..3aca8e28 --- /dev/null +++ b/tests/api_resources/cdn/test_statistics.py @@ -0,0 +1,608 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import ( + UsageSeriesStats, + ResourceUsageStats, + LogsAggregatedStats, + ShieldAggregatedStats, + ResourceAggregatedStats, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestStatistics: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_logs_usage_aggregated(self, client: Gcore) -> None: + statistic = client.cdn.statistics.get_logs_usage_aggregated( + from_="from", + to="to", + ) + assert_matches_type(LogsAggregatedStats, statistic, path=["response"]) + + @parametrize + def test_method_get_logs_usage_aggregated_with_all_params(self, client: Gcore) -> None: + statistic = client.cdn.statistics.get_logs_usage_aggregated( + from_="from", + to="to", + flat=True, + group_by="group_by", + resource=0, + ) + assert_matches_type(LogsAggregatedStats, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_logs_usage_aggregated(self, client: Gcore) -> None: + response = client.cdn.statistics.with_raw_response.get_logs_usage_aggregated( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(LogsAggregatedStats, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_logs_usage_aggregated(self, client: Gcore) -> None: + with client.cdn.statistics.with_streaming_response.get_logs_usage_aggregated( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(LogsAggregatedStats, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_logs_usage_series(self, client: Gcore) -> None: + statistic = client.cdn.statistics.get_logs_usage_series( + from_="from", + to="to", + ) + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + @parametrize + def test_method_get_logs_usage_series_with_all_params(self, client: Gcore) -> None: + statistic = client.cdn.statistics.get_logs_usage_series( + from_="from", + to="to", + resource=0, + ) + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_logs_usage_series(self, client: Gcore) -> None: + response = client.cdn.statistics.with_raw_response.get_logs_usage_series( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_logs_usage_series(self, client: Gcore) -> None: + with client.cdn.statistics.with_streaming_response.get_logs_usage_series( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_resource_usage_aggregated(self, client: Gcore) -> None: + statistic = client.cdn.statistics.get_resource_usage_aggregated( + from_="from", + metrics="metrics", + service="service", + to="to", + ) + assert_matches_type(ResourceAggregatedStats, statistic, path=["response"]) + + @parametrize + def test_method_get_resource_usage_aggregated_with_all_params(self, client: Gcore) -> None: + statistic = client.cdn.statistics.get_resource_usage_aggregated( + from_="from", + metrics="metrics", + service="service", + to="to", + countries="countries", + flat=True, + group_by="group_by", + regions="regions", + resource=0, + ) + assert_matches_type(ResourceAggregatedStats, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_resource_usage_aggregated(self, client: Gcore) -> None: + response = client.cdn.statistics.with_raw_response.get_resource_usage_aggregated( + from_="from", + metrics="metrics", + service="service", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(ResourceAggregatedStats, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_resource_usage_aggregated(self, client: Gcore) -> None: + with client.cdn.statistics.with_streaming_response.get_resource_usage_aggregated( + from_="from", + metrics="metrics", + service="service", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(ResourceAggregatedStats, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_resource_usage_series(self, client: Gcore) -> None: + statistic = client.cdn.statistics.get_resource_usage_series( + from_="from", + granularity="granularity", + metrics="metrics", + service="service", + to="to", + ) + assert_matches_type(ResourceUsageStats, statistic, path=["response"]) + + @parametrize + def test_method_get_resource_usage_series_with_all_params(self, client: Gcore) -> None: + statistic = client.cdn.statistics.get_resource_usage_series( + from_="from", + granularity="granularity", + metrics="metrics", + service="service", + to="to", + countries="countries", + group_by="group_by", + regions="regions", + resource=0, + ) + assert_matches_type(ResourceUsageStats, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_resource_usage_series(self, client: Gcore) -> None: + response = client.cdn.statistics.with_raw_response.get_resource_usage_series( + from_="from", + granularity="granularity", + metrics="metrics", + service="service", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(ResourceUsageStats, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_resource_usage_series(self, client: Gcore) -> None: + with client.cdn.statistics.with_streaming_response.get_resource_usage_series( + from_="from", + granularity="granularity", + metrics="metrics", + service="service", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(ResourceUsageStats, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_shield_usage_aggregated(self, client: Gcore) -> None: + statistic = client.cdn.statistics.get_shield_usage_aggregated( + from_="from", + to="to", + ) + assert_matches_type(ShieldAggregatedStats, statistic, path=["response"]) + + @parametrize + def test_method_get_shield_usage_aggregated_with_all_params(self, client: Gcore) -> None: + statistic = client.cdn.statistics.get_shield_usage_aggregated( + from_="from", + to="to", + flat=True, + group_by="group_by", + resource=0, + ) + assert_matches_type(ShieldAggregatedStats, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_shield_usage_aggregated(self, client: Gcore) -> None: + response = client.cdn.statistics.with_raw_response.get_shield_usage_aggregated( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(ShieldAggregatedStats, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_shield_usage_aggregated(self, client: Gcore) -> None: + with client.cdn.statistics.with_streaming_response.get_shield_usage_aggregated( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(ShieldAggregatedStats, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_shield_usage_series(self, client: Gcore) -> None: + statistic = client.cdn.statistics.get_shield_usage_series( + from_="from", + to="to", + ) + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + @parametrize + def test_method_get_shield_usage_series_with_all_params(self, client: Gcore) -> None: + statistic = client.cdn.statistics.get_shield_usage_series( + from_="from", + to="to", + resource=0, + ) + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_shield_usage_series(self, client: Gcore) -> None: + response = client.cdn.statistics.with_raw_response.get_shield_usage_series( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_shield_usage_series(self, client: Gcore) -> None: + with client.cdn.statistics.with_streaming_response.get_shield_usage_series( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncStatistics: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_logs_usage_aggregated(self, async_client: AsyncGcore) -> None: + statistic = await async_client.cdn.statistics.get_logs_usage_aggregated( + from_="from", + to="to", + ) + assert_matches_type(LogsAggregatedStats, statistic, path=["response"]) + + @parametrize + async def test_method_get_logs_usage_aggregated_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.cdn.statistics.get_logs_usage_aggregated( + from_="from", + to="to", + flat=True, + group_by="group_by", + resource=0, + ) + assert_matches_type(LogsAggregatedStats, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_logs_usage_aggregated(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.statistics.with_raw_response.get_logs_usage_aggregated( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(LogsAggregatedStats, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_logs_usage_aggregated(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.statistics.with_streaming_response.get_logs_usage_aggregated( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(LogsAggregatedStats, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_logs_usage_series(self, async_client: AsyncGcore) -> None: + statistic = await async_client.cdn.statistics.get_logs_usage_series( + from_="from", + to="to", + ) + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + @parametrize + async def test_method_get_logs_usage_series_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.cdn.statistics.get_logs_usage_series( + from_="from", + to="to", + resource=0, + ) + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_logs_usage_series(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.statistics.with_raw_response.get_logs_usage_series( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_logs_usage_series(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.statistics.with_streaming_response.get_logs_usage_series( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_resource_usage_aggregated(self, async_client: AsyncGcore) -> None: + statistic = await async_client.cdn.statistics.get_resource_usage_aggregated( + from_="from", + metrics="metrics", + service="service", + to="to", + ) + assert_matches_type(ResourceAggregatedStats, statistic, path=["response"]) + + @parametrize + async def test_method_get_resource_usage_aggregated_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.cdn.statistics.get_resource_usage_aggregated( + from_="from", + metrics="metrics", + service="service", + to="to", + countries="countries", + flat=True, + group_by="group_by", + regions="regions", + resource=0, + ) + assert_matches_type(ResourceAggregatedStats, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_resource_usage_aggregated(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.statistics.with_raw_response.get_resource_usage_aggregated( + from_="from", + metrics="metrics", + service="service", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(ResourceAggregatedStats, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_resource_usage_aggregated(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.statistics.with_streaming_response.get_resource_usage_aggregated( + from_="from", + metrics="metrics", + service="service", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(ResourceAggregatedStats, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_resource_usage_series(self, async_client: AsyncGcore) -> None: + statistic = await async_client.cdn.statistics.get_resource_usage_series( + from_="from", + granularity="granularity", + metrics="metrics", + service="service", + to="to", + ) + assert_matches_type(ResourceUsageStats, statistic, path=["response"]) + + @parametrize + async def test_method_get_resource_usage_series_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.cdn.statistics.get_resource_usage_series( + from_="from", + granularity="granularity", + metrics="metrics", + service="service", + to="to", + countries="countries", + group_by="group_by", + regions="regions", + resource=0, + ) + assert_matches_type(ResourceUsageStats, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_resource_usage_series(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.statistics.with_raw_response.get_resource_usage_series( + from_="from", + granularity="granularity", + metrics="metrics", + service="service", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(ResourceUsageStats, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_resource_usage_series(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.statistics.with_streaming_response.get_resource_usage_series( + from_="from", + granularity="granularity", + metrics="metrics", + service="service", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(ResourceUsageStats, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_shield_usage_aggregated(self, async_client: AsyncGcore) -> None: + statistic = await async_client.cdn.statistics.get_shield_usage_aggregated( + from_="from", + to="to", + ) + assert_matches_type(ShieldAggregatedStats, statistic, path=["response"]) + + @parametrize + async def test_method_get_shield_usage_aggregated_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.cdn.statistics.get_shield_usage_aggregated( + from_="from", + to="to", + flat=True, + group_by="group_by", + resource=0, + ) + assert_matches_type(ShieldAggregatedStats, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_shield_usage_aggregated(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.statistics.with_raw_response.get_shield_usage_aggregated( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(ShieldAggregatedStats, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_shield_usage_aggregated(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.statistics.with_streaming_response.get_shield_usage_aggregated( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(ShieldAggregatedStats, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_shield_usage_series(self, async_client: AsyncGcore) -> None: + statistic = await async_client.cdn.statistics.get_shield_usage_series( + from_="from", + to="to", + ) + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + @parametrize + async def test_method_get_shield_usage_series_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.cdn.statistics.get_shield_usage_series( + from_="from", + to="to", + resource=0, + ) + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_shield_usage_series(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.statistics.with_raw_response.get_shield_usage_series( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_shield_usage_series(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.statistics.with_streaming_response.get_shield_usage_series( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(UsageSeriesStats, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cdn/test_trusted_ca_certificates.py b/tests/api_resources/cdn/test_trusted_ca_certificates.py new file mode 100644 index 00000000..0d0df832 --- /dev/null +++ b/tests/api_resources/cdn/test_trusted_ca_certificates.py @@ -0,0 +1,355 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import ( + CaCertificate, + CaCertificateList, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTrustedCaCertificates: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + trusted_ca_certificate = client.cdn.trusted_ca_certificates.create( + name="Example CA cert", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIC0zCCAbugAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAwwLZXhh\nbXBsZS5jb20wHhcNMjAwNjI2MTIwMzUzWhcNMjEwNjI2MTIwMzUzWjAWMRQwEgYD\nVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAN4nnSfTsMEnfPgL7rkbImxZAQoND+bpPoX8q16iXZz3fFfqdRk+uEIpU3Brleeg\np0zrrT2eI3+c2h/PRod0Fam4TO6EcfwuboUFzV3j6yw6aWdfBjWZsWBR/FoqWLYq\nb3UejN7yiTYNSiIy3zVpi9pnFM8N8qT+VGBrRDGef2v9JCzhsSSU7wAYM5HKZTp+\nWHojjiyB2hOYqft7A2WlTEDmHFa5UcPHMRZKATUYI1T2TRVqLlSiE2mJ3dFRXGM2\nZAS33J0NVUjkx3w8RmJ7DNflEFJt/6IXdfaokVgfza7LFarrQFQP/YURXEeJT7jm\nDvKpZ/a8wu3ve6N4ykC+CBsCAwEAAaMrMCkwDwYDVR0TBAgwBgEB/wIBADAWBgNV\nHREEDzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAovxY5lm89Eod\nL8CH3dZzIH7nv8MXtwgpv2vth4PDq2btLS8xrqm2SsA/cV+DsbDjh5CxQLoDX+8V\ng8NtY+ipOE0hdJAUo7UVlsxuAY4frkmLL1/RwpjZg+Z2NAxpR7xGWgoMn7CH481w\nAOBypAuCxcfcyyAOttdS+YMRJnpL6z8/C3W0LGkNOs26Qhu1/U8lfz1f9F4XummD\nu2SCmJsAd1PrL1shsyh4HtmFjuY698aTjYUDUleAnx7ytrGlZuLOIeoQi7tcsLJJ\nTPMbxTLgGN2HEkdJerFRBNViuWvqioEyYlzZ3MshOCR2wsL4wrXrCF0Y3cNOYcIh\nZ8z+wUAP2g==\n-----END CERTIFICATE-----\n", + ) + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cdn.trusted_ca_certificates.with_raw_response.create( + name="Example CA cert", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIC0zCCAbugAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAwwLZXhh\nbXBsZS5jb20wHhcNMjAwNjI2MTIwMzUzWhcNMjEwNjI2MTIwMzUzWjAWMRQwEgYD\nVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAN4nnSfTsMEnfPgL7rkbImxZAQoND+bpPoX8q16iXZz3fFfqdRk+uEIpU3Brleeg\np0zrrT2eI3+c2h/PRod0Fam4TO6EcfwuboUFzV3j6yw6aWdfBjWZsWBR/FoqWLYq\nb3UejN7yiTYNSiIy3zVpi9pnFM8N8qT+VGBrRDGef2v9JCzhsSSU7wAYM5HKZTp+\nWHojjiyB2hOYqft7A2WlTEDmHFa5UcPHMRZKATUYI1T2TRVqLlSiE2mJ3dFRXGM2\nZAS33J0NVUjkx3w8RmJ7DNflEFJt/6IXdfaokVgfza7LFarrQFQP/YURXEeJT7jm\nDvKpZ/a8wu3ve6N4ykC+CBsCAwEAAaMrMCkwDwYDVR0TBAgwBgEB/wIBADAWBgNV\nHREEDzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAovxY5lm89Eod\nL8CH3dZzIH7nv8MXtwgpv2vth4PDq2btLS8xrqm2SsA/cV+DsbDjh5CxQLoDX+8V\ng8NtY+ipOE0hdJAUo7UVlsxuAY4frkmLL1/RwpjZg+Z2NAxpR7xGWgoMn7CH481w\nAOBypAuCxcfcyyAOttdS+YMRJnpL6z8/C3W0LGkNOs26Qhu1/U8lfz1f9F4XummD\nu2SCmJsAd1PrL1shsyh4HtmFjuY698aTjYUDUleAnx7ytrGlZuLOIeoQi7tcsLJJ\nTPMbxTLgGN2HEkdJerFRBNViuWvqioEyYlzZ3MshOCR2wsL4wrXrCF0Y3cNOYcIh\nZ8z+wUAP2g==\n-----END CERTIFICATE-----\n", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + trusted_ca_certificate = response.parse() + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cdn.trusted_ca_certificates.with_streaming_response.create( + name="Example CA cert", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIC0zCCAbugAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAwwLZXhh\nbXBsZS5jb20wHhcNMjAwNjI2MTIwMzUzWhcNMjEwNjI2MTIwMzUzWjAWMRQwEgYD\nVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAN4nnSfTsMEnfPgL7rkbImxZAQoND+bpPoX8q16iXZz3fFfqdRk+uEIpU3Brleeg\np0zrrT2eI3+c2h/PRod0Fam4TO6EcfwuboUFzV3j6yw6aWdfBjWZsWBR/FoqWLYq\nb3UejN7yiTYNSiIy3zVpi9pnFM8N8qT+VGBrRDGef2v9JCzhsSSU7wAYM5HKZTp+\nWHojjiyB2hOYqft7A2WlTEDmHFa5UcPHMRZKATUYI1T2TRVqLlSiE2mJ3dFRXGM2\nZAS33J0NVUjkx3w8RmJ7DNflEFJt/6IXdfaokVgfza7LFarrQFQP/YURXEeJT7jm\nDvKpZ/a8wu3ve6N4ykC+CBsCAwEAAaMrMCkwDwYDVR0TBAgwBgEB/wIBADAWBgNV\nHREEDzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAovxY5lm89Eod\nL8CH3dZzIH7nv8MXtwgpv2vth4PDq2btLS8xrqm2SsA/cV+DsbDjh5CxQLoDX+8V\ng8NtY+ipOE0hdJAUo7UVlsxuAY4frkmLL1/RwpjZg+Z2NAxpR7xGWgoMn7CH481w\nAOBypAuCxcfcyyAOttdS+YMRJnpL6z8/C3W0LGkNOs26Qhu1/U8lfz1f9F4XummD\nu2SCmJsAd1PrL1shsyh4HtmFjuY698aTjYUDUleAnx7ytrGlZuLOIeoQi7tcsLJJ\nTPMbxTLgGN2HEkdJerFRBNViuWvqioEyYlzZ3MshOCR2wsL4wrXrCF0Y3cNOYcIh\nZ8z+wUAP2g==\n-----END CERTIFICATE-----\n", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + trusted_ca_certificate = response.parse() + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + trusted_ca_certificate = client.cdn.trusted_ca_certificates.list() + assert_matches_type(CaCertificateList, trusted_ca_certificate, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + trusted_ca_certificate = client.cdn.trusted_ca_certificates.list( + automated=True, + resource_id=0, + validity_not_after_lte="validity_not_after_lte", + ) + assert_matches_type(CaCertificateList, trusted_ca_certificate, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cdn.trusted_ca_certificates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + trusted_ca_certificate = response.parse() + assert_matches_type(CaCertificateList, trusted_ca_certificate, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cdn.trusted_ca_certificates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + trusted_ca_certificate = response.parse() + assert_matches_type(CaCertificateList, trusted_ca_certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + trusted_ca_certificate = client.cdn.trusted_ca_certificates.delete( + 0, + ) + assert trusted_ca_certificate is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cdn.trusted_ca_certificates.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + trusted_ca_certificate = response.parse() + assert trusted_ca_certificate is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cdn.trusted_ca_certificates.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + trusted_ca_certificate = response.parse() + assert trusted_ca_certificate is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + trusted_ca_certificate = client.cdn.trusted_ca_certificates.get( + 0, + ) + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cdn.trusted_ca_certificates.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + trusted_ca_certificate = response.parse() + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cdn.trusted_ca_certificates.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + trusted_ca_certificate = response.parse() + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + trusted_ca_certificate = client.cdn.trusted_ca_certificates.replace( + id=0, + name="Example CA cert 2", + ) + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.cdn.trusted_ca_certificates.with_raw_response.replace( + id=0, + name="Example CA cert 2", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + trusted_ca_certificate = response.parse() + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.cdn.trusted_ca_certificates.with_streaming_response.replace( + id=0, + name="Example CA cert 2", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + trusted_ca_certificate = response.parse() + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncTrustedCaCertificates: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + trusted_ca_certificate = await async_client.cdn.trusted_ca_certificates.create( + name="Example CA cert", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIC0zCCAbugAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAwwLZXhh\nbXBsZS5jb20wHhcNMjAwNjI2MTIwMzUzWhcNMjEwNjI2MTIwMzUzWjAWMRQwEgYD\nVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAN4nnSfTsMEnfPgL7rkbImxZAQoND+bpPoX8q16iXZz3fFfqdRk+uEIpU3Brleeg\np0zrrT2eI3+c2h/PRod0Fam4TO6EcfwuboUFzV3j6yw6aWdfBjWZsWBR/FoqWLYq\nb3UejN7yiTYNSiIy3zVpi9pnFM8N8qT+VGBrRDGef2v9JCzhsSSU7wAYM5HKZTp+\nWHojjiyB2hOYqft7A2WlTEDmHFa5UcPHMRZKATUYI1T2TRVqLlSiE2mJ3dFRXGM2\nZAS33J0NVUjkx3w8RmJ7DNflEFJt/6IXdfaokVgfza7LFarrQFQP/YURXEeJT7jm\nDvKpZ/a8wu3ve6N4ykC+CBsCAwEAAaMrMCkwDwYDVR0TBAgwBgEB/wIBADAWBgNV\nHREEDzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAovxY5lm89Eod\nL8CH3dZzIH7nv8MXtwgpv2vth4PDq2btLS8xrqm2SsA/cV+DsbDjh5CxQLoDX+8V\ng8NtY+ipOE0hdJAUo7UVlsxuAY4frkmLL1/RwpjZg+Z2NAxpR7xGWgoMn7CH481w\nAOBypAuCxcfcyyAOttdS+YMRJnpL6z8/C3W0LGkNOs26Qhu1/U8lfz1f9F4XummD\nu2SCmJsAd1PrL1shsyh4HtmFjuY698aTjYUDUleAnx7ytrGlZuLOIeoQi7tcsLJJ\nTPMbxTLgGN2HEkdJerFRBNViuWvqioEyYlzZ3MshOCR2wsL4wrXrCF0Y3cNOYcIh\nZ8z+wUAP2g==\n-----END CERTIFICATE-----\n", + ) + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.trusted_ca_certificates.with_raw_response.create( + name="Example CA cert", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIC0zCCAbugAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAwwLZXhh\nbXBsZS5jb20wHhcNMjAwNjI2MTIwMzUzWhcNMjEwNjI2MTIwMzUzWjAWMRQwEgYD\nVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAN4nnSfTsMEnfPgL7rkbImxZAQoND+bpPoX8q16iXZz3fFfqdRk+uEIpU3Brleeg\np0zrrT2eI3+c2h/PRod0Fam4TO6EcfwuboUFzV3j6yw6aWdfBjWZsWBR/FoqWLYq\nb3UejN7yiTYNSiIy3zVpi9pnFM8N8qT+VGBrRDGef2v9JCzhsSSU7wAYM5HKZTp+\nWHojjiyB2hOYqft7A2WlTEDmHFa5UcPHMRZKATUYI1T2TRVqLlSiE2mJ3dFRXGM2\nZAS33J0NVUjkx3w8RmJ7DNflEFJt/6IXdfaokVgfza7LFarrQFQP/YURXEeJT7jm\nDvKpZ/a8wu3ve6N4ykC+CBsCAwEAAaMrMCkwDwYDVR0TBAgwBgEB/wIBADAWBgNV\nHREEDzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAovxY5lm89Eod\nL8CH3dZzIH7nv8MXtwgpv2vth4PDq2btLS8xrqm2SsA/cV+DsbDjh5CxQLoDX+8V\ng8NtY+ipOE0hdJAUo7UVlsxuAY4frkmLL1/RwpjZg+Z2NAxpR7xGWgoMn7CH481w\nAOBypAuCxcfcyyAOttdS+YMRJnpL6z8/C3W0LGkNOs26Qhu1/U8lfz1f9F4XummD\nu2SCmJsAd1PrL1shsyh4HtmFjuY698aTjYUDUleAnx7ytrGlZuLOIeoQi7tcsLJJ\nTPMbxTLgGN2HEkdJerFRBNViuWvqioEyYlzZ3MshOCR2wsL4wrXrCF0Y3cNOYcIh\nZ8z+wUAP2g==\n-----END CERTIFICATE-----\n", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + trusted_ca_certificate = await response.parse() + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.trusted_ca_certificates.with_streaming_response.create( + name="Example CA cert", + ssl_certificate="-----BEGIN CERTIFICATE-----\nMIIC0zCCAbugAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAwwLZXhh\nbXBsZS5jb20wHhcNMjAwNjI2MTIwMzUzWhcNMjEwNjI2MTIwMzUzWjAWMRQwEgYD\nVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAN4nnSfTsMEnfPgL7rkbImxZAQoND+bpPoX8q16iXZz3fFfqdRk+uEIpU3Brleeg\np0zrrT2eI3+c2h/PRod0Fam4TO6EcfwuboUFzV3j6yw6aWdfBjWZsWBR/FoqWLYq\nb3UejN7yiTYNSiIy3zVpi9pnFM8N8qT+VGBrRDGef2v9JCzhsSSU7wAYM5HKZTp+\nWHojjiyB2hOYqft7A2WlTEDmHFa5UcPHMRZKATUYI1T2TRVqLlSiE2mJ3dFRXGM2\nZAS33J0NVUjkx3w8RmJ7DNflEFJt/6IXdfaokVgfza7LFarrQFQP/YURXEeJT7jm\nDvKpZ/a8wu3ve6N4ykC+CBsCAwEAAaMrMCkwDwYDVR0TBAgwBgEB/wIBADAWBgNV\nHREEDzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAovxY5lm89Eod\nL8CH3dZzIH7nv8MXtwgpv2vth4PDq2btLS8xrqm2SsA/cV+DsbDjh5CxQLoDX+8V\ng8NtY+ipOE0hdJAUo7UVlsxuAY4frkmLL1/RwpjZg+Z2NAxpR7xGWgoMn7CH481w\nAOBypAuCxcfcyyAOttdS+YMRJnpL6z8/C3W0LGkNOs26Qhu1/U8lfz1f9F4XummD\nu2SCmJsAd1PrL1shsyh4HtmFjuY698aTjYUDUleAnx7ytrGlZuLOIeoQi7tcsLJJ\nTPMbxTLgGN2HEkdJerFRBNViuWvqioEyYlzZ3MshOCR2wsL4wrXrCF0Y3cNOYcIh\nZ8z+wUAP2g==\n-----END CERTIFICATE-----\n", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + trusted_ca_certificate = await response.parse() + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + trusted_ca_certificate = await async_client.cdn.trusted_ca_certificates.list() + assert_matches_type(CaCertificateList, trusted_ca_certificate, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + trusted_ca_certificate = await async_client.cdn.trusted_ca_certificates.list( + automated=True, + resource_id=0, + validity_not_after_lte="validity_not_after_lte", + ) + assert_matches_type(CaCertificateList, trusted_ca_certificate, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.trusted_ca_certificates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + trusted_ca_certificate = await response.parse() + assert_matches_type(CaCertificateList, trusted_ca_certificate, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.trusted_ca_certificates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + trusted_ca_certificate = await response.parse() + assert_matches_type(CaCertificateList, trusted_ca_certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + trusted_ca_certificate = await async_client.cdn.trusted_ca_certificates.delete( + 0, + ) + assert trusted_ca_certificate is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.trusted_ca_certificates.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + trusted_ca_certificate = await response.parse() + assert trusted_ca_certificate is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.trusted_ca_certificates.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + trusted_ca_certificate = await response.parse() + assert trusted_ca_certificate is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + trusted_ca_certificate = await async_client.cdn.trusted_ca_certificates.get( + 0, + ) + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.trusted_ca_certificates.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + trusted_ca_certificate = await response.parse() + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.trusted_ca_certificates.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + trusted_ca_certificate = await response.parse() + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + trusted_ca_certificate = await async_client.cdn.trusted_ca_certificates.replace( + id=0, + name="Example CA cert 2", + ) + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.trusted_ca_certificates.with_raw_response.replace( + id=0, + name="Example CA cert 2", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + trusted_ca_certificate = await response.parse() + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.trusted_ca_certificates.with_streaming_response.replace( + id=0, + name="Example CA cert 2", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + trusted_ca_certificate = await response.parse() + assert_matches_type(CaCertificate, trusted_ca_certificate, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/__init__.py b/tests/api_resources/cloud/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/baremetal/__init__.py b/tests/api_resources/cloud/baremetal/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/baremetal/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/baremetal/test_flavors.py b/tests/api_resources/cloud/baremetal/test_flavors.py new file mode 100644 index 00000000..18da226a --- /dev/null +++ b/tests/api_resources/cloud/baremetal/test_flavors.py @@ -0,0 +1,120 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import BaremetalFlavorList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFlavors: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + flavor = client.cloud.baremetal.flavors.list( + project_id=0, + region_id=0, + ) + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + flavor = client.cloud.baremetal.flavors.list( + project_id=0, + region_id=0, + disabled=True, + exclude_linux=True, + exclude_windows=True, + include_capacity=True, + include_prices=True, + include_reservation_stock=True, + ) + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.baremetal.flavors.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = response.parse() + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.baremetal.flavors.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = response.parse() + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncFlavors: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.baremetal.flavors.list( + project_id=0, + region_id=0, + ) + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.baremetal.flavors.list( + project_id=0, + region_id=0, + disabled=True, + exclude_linux=True, + exclude_windows=True, + include_capacity=True, + include_prices=True, + include_reservation_stock=True, + ) + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.baremetal.flavors.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = await response.parse() + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.baremetal.flavors.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = await response.parse() + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/baremetal/test_images.py b/tests/api_resources/cloud/baremetal/test_images.py new file mode 100644 index 00000000..235f970b --- /dev/null +++ b/tests/api_resources/cloud/baremetal/test_images.py @@ -0,0 +1,118 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import ImageList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestImages: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + image = client.cloud.baremetal.images.list( + project_id=0, + region_id=0, + ) + assert_matches_type(ImageList, image, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + image = client.cloud.baremetal.images.list( + project_id=0, + region_id=0, + include_prices=True, + private="private", + tag_key=["string"], + tag_key_value="tag_key_value", + visibility="private", + ) + assert_matches_type(ImageList, image, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.baremetal.images.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(ImageList, image, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.baremetal.images.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(ImageList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncImages: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.baremetal.images.list( + project_id=0, + region_id=0, + ) + assert_matches_type(ImageList, image, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.baremetal.images.list( + project_id=0, + region_id=0, + include_prices=True, + private="private", + tag_key=["string"], + tag_key_value="tag_key_value", + visibility="private", + ) + assert_matches_type(ImageList, image, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.baremetal.images.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(ImageList, image, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.baremetal.images.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(ImageList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/baremetal/test_servers.py b/tests/api_resources/cloud/baremetal/test_servers.py new file mode 100644 index 00000000..564217ee --- /dev/null +++ b/tests/api_resources/cloud/baremetal/test_servers.py @@ -0,0 +1,423 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import TaskIDList +from gcore.types.cloud.baremetal import BaremetalServer + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestServers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + server = client.cloud.baremetal.servers.create( + project_id=1, + region_id=1, + flavor="bm2-hf-medium", + interfaces=[{"type": "external"}], + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + server = client.cloud.baremetal.servers.create( + project_id=1, + region_id=1, + flavor="bm2-hf-medium", + interfaces=[ + { + "type": "external", + "interface_name": "eth0", + "ip_family": "ipv4", + "port_group": 0, + } + ], + app_config={"foo": "bar"}, + apptemplate_id="apptemplate_id", + ddos_profile={ + "profile_template": 123, + "fields": [ + { + "base_field": 10, + "field_name": None, + "field_value": [45046, 45047], + "value": None, + } + ], + }, + image_id="image_id", + name="my-bare-metal", + name_template="name_template", + password="password", + ssh_key_name="my-ssh-key", + tags={"my-tag": "my-tag-value"}, + user_data="user_data", + username="username", + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.baremetal.servers.with_raw_response.create( + project_id=1, + region_id=1, + flavor="bm2-hf-medium", + interfaces=[{"type": "external"}], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.baremetal.servers.with_streaming_response.create( + project_id=1, + region_id=1, + flavor="bm2-hf-medium", + interfaces=[{"type": "external"}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + server = client.cloud.baremetal.servers.list( + project_id=1, + region_id=1, + ) + assert_matches_type(SyncOffsetPage[BaremetalServer], server, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + server = client.cloud.baremetal.servers.list( + project_id=1, + region_id=1, + changes_before=parse_datetime("2025-10-01T12:00:00Z"), + changes_since=parse_datetime("2025-10-01T12:00:00Z"), + flavor_id="bm2-hf-small", + flavor_prefix="bm2-", + include_k8s=True, + ip="192.168.0.1", + limit=1000, + name="name", + offset=0, + only_isolated=True, + only_with_fixed_external_ip=True, + order_by="name.asc", + profile_name="profile_name", + protection_status="Active", + status="ACTIVE", + tag_key_value="tag_key_value", + tag_value=["value1", "value2"], + type_ddos_profile="advanced", + uuid="b5b4d65d-945f-4b98-ab6f-332319c724ef", + with_ddos=True, + with_interfaces_name=True, + ) + assert_matches_type(SyncOffsetPage[BaremetalServer], server, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.baremetal.servers.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = response.parse() + assert_matches_type(SyncOffsetPage[BaremetalServer], server, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.baremetal.servers.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = response.parse() + assert_matches_type(SyncOffsetPage[BaremetalServer], server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_rebuild(self, client: Gcore) -> None: + server = client.cloud.baremetal.servers.rebuild( + server_id="024a29e-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_method_rebuild_with_all_params(self, client: Gcore) -> None: + server = client.cloud.baremetal.servers.rebuild( + server_id="024a29e-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + image_id="b5b4d65d-945f-4b98-ab6f-332319c724ef", + user_data="aGVsbG9fd29ybGQ=", + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_raw_response_rebuild(self, client: Gcore) -> None: + response = client.cloud.baremetal.servers.with_raw_response.rebuild( + server_id="024a29e-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_streaming_response_rebuild(self, client: Gcore) -> None: + with client.cloud.baremetal.servers.with_streaming_response.rebuild( + server_id="024a29e-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_rebuild(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `server_id` but received ''"): + client.cloud.baremetal.servers.with_raw_response.rebuild( + server_id="", + project_id=1, + region_id=1, + ) + + +class TestAsyncServers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.baremetal.servers.create( + project_id=1, + region_id=1, + flavor="bm2-hf-medium", + interfaces=[{"type": "external"}], + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.baremetal.servers.create( + project_id=1, + region_id=1, + flavor="bm2-hf-medium", + interfaces=[ + { + "type": "external", + "interface_name": "eth0", + "ip_family": "ipv4", + "port_group": 0, + } + ], + app_config={"foo": "bar"}, + apptemplate_id="apptemplate_id", + ddos_profile={ + "profile_template": 123, + "fields": [ + { + "base_field": 10, + "field_name": None, + "field_value": [45046, 45047], + "value": None, + } + ], + }, + image_id="image_id", + name="my-bare-metal", + name_template="name_template", + password="password", + ssh_key_name="my-ssh-key", + tags={"my-tag": "my-tag-value"}, + user_data="user_data", + username="username", + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.baremetal.servers.with_raw_response.create( + project_id=1, + region_id=1, + flavor="bm2-hf-medium", + interfaces=[{"type": "external"}], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = await response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.baremetal.servers.with_streaming_response.create( + project_id=1, + region_id=1, + flavor="bm2-hf-medium", + interfaces=[{"type": "external"}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = await response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.baremetal.servers.list( + project_id=1, + region_id=1, + ) + assert_matches_type(AsyncOffsetPage[BaremetalServer], server, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.baremetal.servers.list( + project_id=1, + region_id=1, + changes_before=parse_datetime("2025-10-01T12:00:00Z"), + changes_since=parse_datetime("2025-10-01T12:00:00Z"), + flavor_id="bm2-hf-small", + flavor_prefix="bm2-", + include_k8s=True, + ip="192.168.0.1", + limit=1000, + name="name", + offset=0, + only_isolated=True, + only_with_fixed_external_ip=True, + order_by="name.asc", + profile_name="profile_name", + protection_status="Active", + status="ACTIVE", + tag_key_value="tag_key_value", + tag_value=["value1", "value2"], + type_ddos_profile="advanced", + uuid="b5b4d65d-945f-4b98-ab6f-332319c724ef", + with_ddos=True, + with_interfaces_name=True, + ) + assert_matches_type(AsyncOffsetPage[BaremetalServer], server, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.baremetal.servers.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = await response.parse() + assert_matches_type(AsyncOffsetPage[BaremetalServer], server, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.baremetal.servers.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = await response.parse() + assert_matches_type(AsyncOffsetPage[BaremetalServer], server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_rebuild(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.baremetal.servers.rebuild( + server_id="024a29e-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_method_rebuild_with_all_params(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.baremetal.servers.rebuild( + server_id="024a29e-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + image_id="b5b4d65d-945f-4b98-ab6f-332319c724ef", + user_data="aGVsbG9fd29ybGQ=", + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_raw_response_rebuild(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.baremetal.servers.with_raw_response.rebuild( + server_id="024a29e-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = await response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_streaming_response_rebuild(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.baremetal.servers.with_streaming_response.rebuild( + server_id="024a29e-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = await response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_rebuild(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `server_id` but received ''"): + await async_client.cloud.baremetal.servers.with_raw_response.rebuild( + server_id="", + project_id=1, + region_id=1, + ) diff --git a/tests/api_resources/cloud/databases/__init__.py b/tests/api_resources/cloud/databases/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/databases/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/databases/postgres/__init__.py b/tests/api_resources/cloud/databases/postgres/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/databases/postgres/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/databases/postgres/clusters/__init__.py b/tests/api_resources/cloud/databases/postgres/clusters/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/databases/postgres/clusters/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/databases/postgres/clusters/test_user_credentials.py b/tests/api_resources/cloud/databases/postgres/clusters/test_user_credentials.py new file mode 100644 index 00000000..28169d78 --- /dev/null +++ b/tests/api_resources/cloud/databases/postgres/clusters/test_user_credentials.py @@ -0,0 +1,256 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.databases.postgres.clusters import PostgresUserCredentials + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestUserCredentials: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + user_credential = client.cloud.databases.postgres.clusters.user_credentials.get( + username="username", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + assert_matches_type(PostgresUserCredentials, user_credential, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.databases.postgres.clusters.user_credentials.with_raw_response.get( + username="username", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user_credential = response.parse() + assert_matches_type(PostgresUserCredentials, user_credential, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.databases.postgres.clusters.user_credentials.with_streaming_response.get( + username="username", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user_credential = response.parse() + assert_matches_type(PostgresUserCredentials, user_credential, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.databases.postgres.clusters.user_credentials.with_raw_response.get( + username="username", + project_id=0, + region_id=0, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `username` but received ''"): + client.cloud.databases.postgres.clusters.user_credentials.with_raw_response.get( + username="", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + + @parametrize + def test_method_regenerate(self, client: Gcore) -> None: + user_credential = client.cloud.databases.postgres.clusters.user_credentials.regenerate( + username="username", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + assert_matches_type(PostgresUserCredentials, user_credential, path=["response"]) + + @parametrize + def test_raw_response_regenerate(self, client: Gcore) -> None: + response = client.cloud.databases.postgres.clusters.user_credentials.with_raw_response.regenerate( + username="username", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user_credential = response.parse() + assert_matches_type(PostgresUserCredentials, user_credential, path=["response"]) + + @parametrize + def test_streaming_response_regenerate(self, client: Gcore) -> None: + with client.cloud.databases.postgres.clusters.user_credentials.with_streaming_response.regenerate( + username="username", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user_credential = response.parse() + assert_matches_type(PostgresUserCredentials, user_credential, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_regenerate(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.databases.postgres.clusters.user_credentials.with_raw_response.regenerate( + username="username", + project_id=0, + region_id=0, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `username` but received ''"): + client.cloud.databases.postgres.clusters.user_credentials.with_raw_response.regenerate( + username="", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + + +class TestAsyncUserCredentials: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + user_credential = await async_client.cloud.databases.postgres.clusters.user_credentials.get( + username="username", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + assert_matches_type(PostgresUserCredentials, user_credential, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.databases.postgres.clusters.user_credentials.with_raw_response.get( + username="username", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user_credential = await response.parse() + assert_matches_type(PostgresUserCredentials, user_credential, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.databases.postgres.clusters.user_credentials.with_streaming_response.get( + username="username", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user_credential = await response.parse() + assert_matches_type(PostgresUserCredentials, user_credential, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.databases.postgres.clusters.user_credentials.with_raw_response.get( + username="username", + project_id=0, + region_id=0, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `username` but received ''"): + await async_client.cloud.databases.postgres.clusters.user_credentials.with_raw_response.get( + username="", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + + @parametrize + async def test_method_regenerate(self, async_client: AsyncGcore) -> None: + user_credential = await async_client.cloud.databases.postgres.clusters.user_credentials.regenerate( + username="username", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + assert_matches_type(PostgresUserCredentials, user_credential, path=["response"]) + + @parametrize + async def test_raw_response_regenerate(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.databases.postgres.clusters.user_credentials.with_raw_response.regenerate( + username="username", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user_credential = await response.parse() + assert_matches_type(PostgresUserCredentials, user_credential, path=["response"]) + + @parametrize + async def test_streaming_response_regenerate(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.databases.postgres.clusters.user_credentials.with_streaming_response.regenerate( + username="username", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user_credential = await response.parse() + assert_matches_type(PostgresUserCredentials, user_credential, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_regenerate(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.databases.postgres.clusters.user_credentials.with_raw_response.regenerate( + username="username", + project_id=0, + region_id=0, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `username` but received ''"): + await async_client.cloud.databases.postgres.clusters.user_credentials.with_raw_response.regenerate( + username="", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) diff --git a/tests/api_resources/cloud/databases/postgres/test_clusters.py b/tests/api_resources/cloud/databases/postgres/test_clusters.py new file mode 100644 index 00000000..224aa613 --- /dev/null +++ b/tests/api_resources/cloud/databases/postgres/test_clusters.py @@ -0,0 +1,731 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import TaskIDList +from gcore.types.cloud.databases.postgres import ( + PostgresCluster, + PostgresClusterShort, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestClusters: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + cluster = client.cloud.databases.postgres.clusters.create( + project_id=0, + region_id=0, + cluster_name="3", + flavor={ + "cpu": 1, + "memory_gib": 1, + }, + high_availability={"replication_mode": "sync"}, + network={ + "acl": ["92.33.34.127"], + "network_type": "public", + }, + pg_server_configuration={ + "pg_conf": "\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + "version": "version", + }, + storage={ + "size_gib": 100, + "type": "ssd-hiiops", + }, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.databases.postgres.clusters.create( + project_id=0, + region_id=0, + cluster_name="3", + flavor={ + "cpu": 1, + "memory_gib": 1, + }, + high_availability={"replication_mode": "sync"}, + network={ + "acl": ["92.33.34.127"], + "network_type": "public", + }, + pg_server_configuration={ + "pg_conf": "\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + "version": "version", + "pooler": { + "mode": "transaction", + "type": "pgbouncer", + }, + }, + storage={ + "size_gib": 100, + "type": "ssd-hiiops", + }, + databases=[ + { + "name": "mydatabase", + "owner": "myuser", + } + ], + users=[ + { + "name": "myuser", + "role_attributes": ["INHERIT"], + } + ], + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.databases.postgres.clusters.with_raw_response.create( + project_id=0, + region_id=0, + cluster_name="3", + flavor={ + "cpu": 1, + "memory_gib": 1, + }, + high_availability={"replication_mode": "sync"}, + network={ + "acl": ["92.33.34.127"], + "network_type": "public", + }, + pg_server_configuration={ + "pg_conf": "\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + "version": "version", + }, + storage={ + "size_gib": 100, + "type": "ssd-hiiops", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.databases.postgres.clusters.with_streaming_response.create( + project_id=0, + region_id=0, + cluster_name="3", + flavor={ + "cpu": 1, + "memory_gib": 1, + }, + high_availability={"replication_mode": "sync"}, + network={ + "acl": ["92.33.34.127"], + "network_type": "public", + }, + pg_server_configuration={ + "pg_conf": "\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + "version": "version", + }, + storage={ + "size_gib": 100, + "type": "ssd-hiiops", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + cluster = client.cloud.databases.postgres.clusters.update( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.databases.postgres.clusters.update( + cluster_name="cluster_name", + project_id=0, + region_id=0, + databases=[ + { + "name": "mydatabase", + "owner": "myuser", + } + ], + flavor={ + "cpu": 1, + "memory_gib": 1, + }, + high_availability={"replication_mode": "sync"}, + network={ + "acl": ["92.33.34.127"], + "network_type": "public", + }, + pg_server_configuration={ + "pg_conf": "\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + "pooler": { + "mode": "transaction", + "type": "pgbouncer", + }, + "version": "15", + }, + storage={"size_gib": 100}, + users=[ + { + "name": "myuser", + "role_attributes": ["INHERIT"], + } + ], + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.databases.postgres.clusters.with_raw_response.update( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.databases.postgres.clusters.with_streaming_response.update( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.databases.postgres.clusters.with_raw_response.update( + cluster_name="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + cluster = client.cloud.databases.postgres.clusters.list( + project_id=0, + region_id=0, + ) + assert_matches_type(SyncOffsetPage[PostgresClusterShort], cluster, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.databases.postgres.clusters.list( + project_id=0, + region_id=0, + limit=0, + offset=0, + ) + assert_matches_type(SyncOffsetPage[PostgresClusterShort], cluster, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.databases.postgres.clusters.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(SyncOffsetPage[PostgresClusterShort], cluster, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.databases.postgres.clusters.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(SyncOffsetPage[PostgresClusterShort], cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + cluster = client.cloud.databases.postgres.clusters.delete( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.databases.postgres.clusters.with_raw_response.delete( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.databases.postgres.clusters.with_streaming_response.delete( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.databases.postgres.clusters.with_raw_response.delete( + cluster_name="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + cluster = client.cloud.databases.postgres.clusters.get( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + assert_matches_type(PostgresCluster, cluster, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.databases.postgres.clusters.with_raw_response.get( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(PostgresCluster, cluster, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.databases.postgres.clusters.with_streaming_response.get( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(PostgresCluster, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.databases.postgres.clusters.with_raw_response.get( + cluster_name="", + project_id=0, + region_id=0, + ) + + +class TestAsyncClusters: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.databases.postgres.clusters.create( + project_id=0, + region_id=0, + cluster_name="3", + flavor={ + "cpu": 1, + "memory_gib": 1, + }, + high_availability={"replication_mode": "sync"}, + network={ + "acl": ["92.33.34.127"], + "network_type": "public", + }, + pg_server_configuration={ + "pg_conf": "\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + "version": "version", + }, + storage={ + "size_gib": 100, + "type": "ssd-hiiops", + }, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.databases.postgres.clusters.create( + project_id=0, + region_id=0, + cluster_name="3", + flavor={ + "cpu": 1, + "memory_gib": 1, + }, + high_availability={"replication_mode": "sync"}, + network={ + "acl": ["92.33.34.127"], + "network_type": "public", + }, + pg_server_configuration={ + "pg_conf": "\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + "version": "version", + "pooler": { + "mode": "transaction", + "type": "pgbouncer", + }, + }, + storage={ + "size_gib": 100, + "type": "ssd-hiiops", + }, + databases=[ + { + "name": "mydatabase", + "owner": "myuser", + } + ], + users=[ + { + "name": "myuser", + "role_attributes": ["INHERIT"], + } + ], + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.databases.postgres.clusters.with_raw_response.create( + project_id=0, + region_id=0, + cluster_name="3", + flavor={ + "cpu": 1, + "memory_gib": 1, + }, + high_availability={"replication_mode": "sync"}, + network={ + "acl": ["92.33.34.127"], + "network_type": "public", + }, + pg_server_configuration={ + "pg_conf": "\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + "version": "version", + }, + storage={ + "size_gib": 100, + "type": "ssd-hiiops", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.databases.postgres.clusters.with_streaming_response.create( + project_id=0, + region_id=0, + cluster_name="3", + flavor={ + "cpu": 1, + "memory_gib": 1, + }, + high_availability={"replication_mode": "sync"}, + network={ + "acl": ["92.33.34.127"], + "network_type": "public", + }, + pg_server_configuration={ + "pg_conf": "\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + "version": "version", + }, + storage={ + "size_gib": 100, + "type": "ssd-hiiops", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.databases.postgres.clusters.update( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.databases.postgres.clusters.update( + cluster_name="cluster_name", + project_id=0, + region_id=0, + databases=[ + { + "name": "mydatabase", + "owner": "myuser", + } + ], + flavor={ + "cpu": 1, + "memory_gib": 1, + }, + high_availability={"replication_mode": "sync"}, + network={ + "acl": ["92.33.34.127"], + "network_type": "public", + }, + pg_server_configuration={ + "pg_conf": "\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + "pooler": { + "mode": "transaction", + "type": "pgbouncer", + }, + "version": "15", + }, + storage={"size_gib": 100}, + users=[ + { + "name": "myuser", + "role_attributes": ["INHERIT"], + } + ], + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.databases.postgres.clusters.with_raw_response.update( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.databases.postgres.clusters.with_streaming_response.update( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.databases.postgres.clusters.with_raw_response.update( + cluster_name="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.databases.postgres.clusters.list( + project_id=0, + region_id=0, + ) + assert_matches_type(AsyncOffsetPage[PostgresClusterShort], cluster, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.databases.postgres.clusters.list( + project_id=0, + region_id=0, + limit=0, + offset=0, + ) + assert_matches_type(AsyncOffsetPage[PostgresClusterShort], cluster, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.databases.postgres.clusters.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(AsyncOffsetPage[PostgresClusterShort], cluster, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.databases.postgres.clusters.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(AsyncOffsetPage[PostgresClusterShort], cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.databases.postgres.clusters.delete( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.databases.postgres.clusters.with_raw_response.delete( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.databases.postgres.clusters.with_streaming_response.delete( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.databases.postgres.clusters.with_raw_response.delete( + cluster_name="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.databases.postgres.clusters.get( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + assert_matches_type(PostgresCluster, cluster, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.databases.postgres.clusters.with_raw_response.get( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(PostgresCluster, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.databases.postgres.clusters.with_streaming_response.get( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(PostgresCluster, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.databases.postgres.clusters.with_raw_response.get( + cluster_name="", + project_id=0, + region_id=0, + ) diff --git a/tests/api_resources/cloud/databases/postgres/test_configurations.py b/tests/api_resources/cloud/databases/postgres/test_configurations.py new file mode 100644 index 00000000..635483f0 --- /dev/null +++ b/tests/api_resources/cloud/databases/postgres/test_configurations.py @@ -0,0 +1,92 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.databases.postgres import PostgresConfiguration + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestConfigurations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + configuration = client.cloud.databases.postgres.configurations.get( + project_id=0, + region_id=0, + ) + assert_matches_type(PostgresConfiguration, configuration, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.databases.postgres.configurations.with_raw_response.get( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + configuration = response.parse() + assert_matches_type(PostgresConfiguration, configuration, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.databases.postgres.configurations.with_streaming_response.get( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + configuration = response.parse() + assert_matches_type(PostgresConfiguration, configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncConfigurations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + configuration = await async_client.cloud.databases.postgres.configurations.get( + project_id=0, + region_id=0, + ) + assert_matches_type(PostgresConfiguration, configuration, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.databases.postgres.configurations.with_raw_response.get( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + configuration = await response.parse() + assert_matches_type(PostgresConfiguration, configuration, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.databases.postgres.configurations.with_streaming_response.get( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + configuration = await response.parse() + assert_matches_type(PostgresConfiguration, configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/databases/postgres/test_custom_configurations.py b/tests/api_resources/cloud/databases/postgres/test_custom_configurations.py new file mode 100644 index 00000000..1f6935d3 --- /dev/null +++ b/tests/api_resources/cloud/databases/postgres/test_custom_configurations.py @@ -0,0 +1,104 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.databases.postgres import PgConfValidation + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCustomConfigurations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_validate(self, client: Gcore) -> None: + custom_configuration = client.cloud.databases.postgres.custom_configurations.validate( + project_id=0, + region_id=0, + pg_conf="\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + version="15", + ) + assert_matches_type(PgConfValidation, custom_configuration, path=["response"]) + + @parametrize + def test_raw_response_validate(self, client: Gcore) -> None: + response = client.cloud.databases.postgres.custom_configurations.with_raw_response.validate( + project_id=0, + region_id=0, + pg_conf="\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + version="15", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_configuration = response.parse() + assert_matches_type(PgConfValidation, custom_configuration, path=["response"]) + + @parametrize + def test_streaming_response_validate(self, client: Gcore) -> None: + with client.cloud.databases.postgres.custom_configurations.with_streaming_response.validate( + project_id=0, + region_id=0, + pg_conf="\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + version="15", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_configuration = response.parse() + assert_matches_type(PgConfValidation, custom_configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncCustomConfigurations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_validate(self, async_client: AsyncGcore) -> None: + custom_configuration = await async_client.cloud.databases.postgres.custom_configurations.validate( + project_id=0, + region_id=0, + pg_conf="\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + version="15", + ) + assert_matches_type(PgConfValidation, custom_configuration, path=["response"]) + + @parametrize + async def test_raw_response_validate(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.databases.postgres.custom_configurations.with_raw_response.validate( + project_id=0, + region_id=0, + pg_conf="\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + version="15", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_configuration = await response.parse() + assert_matches_type(PgConfValidation, custom_configuration, path=["response"]) + + @parametrize + async def test_streaming_response_validate(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.databases.postgres.custom_configurations.with_streaming_response.validate( + project_id=0, + region_id=0, + pg_conf="\nlisten_addresses = 'localhost'\nport = 5432\nmax_connections = 100\nshared_buffers = 128MB\nlogging_collector = on", + version="15", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_configuration = await response.parse() + assert_matches_type(PgConfValidation, custom_configuration, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/file_shares/__init__.py b/tests/api_resources/cloud/file_shares/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/file_shares/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/file_shares/test_access_rules.py b/tests/api_resources/cloud/file_shares/test_access_rules.py new file mode 100644 index 00000000..e85ffcd5 --- /dev/null +++ b/tests/api_resources/cloud/file_shares/test_access_rules.py @@ -0,0 +1,340 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.file_shares import AccessRule, AccessRuleList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAccessRules: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + access_rule = client.cloud.file_shares.access_rules.create( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + access_mode="ro", + ip_address="192.168.1.1", + ) + assert_matches_type(AccessRule, access_rule, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.file_shares.access_rules.with_raw_response.create( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + access_mode="ro", + ip_address="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + access_rule = response.parse() + assert_matches_type(AccessRule, access_rule, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.file_shares.access_rules.with_streaming_response.create( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + access_mode="ro", + ip_address="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + access_rule = response.parse() + assert_matches_type(AccessRule, access_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + client.cloud.file_shares.access_rules.with_raw_response.create( + file_share_id="", + project_id=1, + region_id=1, + access_mode="ro", + ip_address="192.168.1.1", + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + access_rule = client.cloud.file_shares.access_rules.list( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + assert_matches_type(AccessRuleList, access_rule, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.file_shares.access_rules.with_raw_response.list( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + access_rule = response.parse() + assert_matches_type(AccessRuleList, access_rule, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.file_shares.access_rules.with_streaming_response.list( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + access_rule = response.parse() + assert_matches_type(AccessRuleList, access_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + client.cloud.file_shares.access_rules.with_raw_response.list( + file_share_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + access_rule = client.cloud.file_shares.access_rules.delete( + access_rule_id="4f09d7dd-f1f8-4352-b015-741b2192db47", + project_id=1, + region_id=1, + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + ) + assert access_rule is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.file_shares.access_rules.with_raw_response.delete( + access_rule_id="4f09d7dd-f1f8-4352-b015-741b2192db47", + project_id=1, + region_id=1, + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + access_rule = response.parse() + assert access_rule is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.file_shares.access_rules.with_streaming_response.delete( + access_rule_id="4f09d7dd-f1f8-4352-b015-741b2192db47", + project_id=1, + region_id=1, + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + access_rule = response.parse() + assert access_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + client.cloud.file_shares.access_rules.with_raw_response.delete( + access_rule_id="4f09d7dd-f1f8-4352-b015-741b2192db47", + project_id=1, + region_id=1, + file_share_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `access_rule_id` but received ''"): + client.cloud.file_shares.access_rules.with_raw_response.delete( + access_rule_id="", + project_id=1, + region_id=1, + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + ) + + +class TestAsyncAccessRules: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + access_rule = await async_client.cloud.file_shares.access_rules.create( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + access_mode="ro", + ip_address="192.168.1.1", + ) + assert_matches_type(AccessRule, access_rule, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.file_shares.access_rules.with_raw_response.create( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + access_mode="ro", + ip_address="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + access_rule = await response.parse() + assert_matches_type(AccessRule, access_rule, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.file_shares.access_rules.with_streaming_response.create( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + access_mode="ro", + ip_address="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + access_rule = await response.parse() + assert_matches_type(AccessRule, access_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + await async_client.cloud.file_shares.access_rules.with_raw_response.create( + file_share_id="", + project_id=1, + region_id=1, + access_mode="ro", + ip_address="192.168.1.1", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + access_rule = await async_client.cloud.file_shares.access_rules.list( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + assert_matches_type(AccessRuleList, access_rule, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.file_shares.access_rules.with_raw_response.list( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + access_rule = await response.parse() + assert_matches_type(AccessRuleList, access_rule, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.file_shares.access_rules.with_streaming_response.list( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + access_rule = await response.parse() + assert_matches_type(AccessRuleList, access_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + await async_client.cloud.file_shares.access_rules.with_raw_response.list( + file_share_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + access_rule = await async_client.cloud.file_shares.access_rules.delete( + access_rule_id="4f09d7dd-f1f8-4352-b015-741b2192db47", + project_id=1, + region_id=1, + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + ) + assert access_rule is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.file_shares.access_rules.with_raw_response.delete( + access_rule_id="4f09d7dd-f1f8-4352-b015-741b2192db47", + project_id=1, + region_id=1, + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + access_rule = await response.parse() + assert access_rule is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.file_shares.access_rules.with_streaming_response.delete( + access_rule_id="4f09d7dd-f1f8-4352-b015-741b2192db47", + project_id=1, + region_id=1, + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + access_rule = await response.parse() + assert access_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + await async_client.cloud.file_shares.access_rules.with_raw_response.delete( + access_rule_id="4f09d7dd-f1f8-4352-b015-741b2192db47", + project_id=1, + region_id=1, + file_share_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `access_rule_id` but received ''"): + await async_client.cloud.file_shares.access_rules.with_raw_response.delete( + access_rule_id="", + project_id=1, + region_id=1, + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + ) diff --git a/tests/api_resources/cloud/gpu_baremetal/__init__.py b/tests/api_resources/cloud/gpu_baremetal/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/gpu_baremetal/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/gpu_baremetal/clusters/__init__.py b/tests/api_resources/cloud/gpu_baremetal/clusters/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/gpu_baremetal/clusters/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/gpu_baremetal/clusters/test_flavors.py b/tests/api_resources/cloud/gpu_baremetal/clusters/test_flavors.py new file mode 100644 index 00000000..b19b4b99 --- /dev/null +++ b/tests/api_resources/cloud/gpu_baremetal/clusters/test_flavors.py @@ -0,0 +1,112 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.gpu_baremetal.clusters import GPUBaremetalFlavorList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFlavors: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + flavor = client.cloud.gpu_baremetal.clusters.flavors.list( + project_id=1, + region_id=7, + ) + assert_matches_type(GPUBaremetalFlavorList, flavor, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + flavor = client.cloud.gpu_baremetal.clusters.flavors.list( + project_id=1, + region_id=7, + hide_disabled=True, + include_prices=True, + ) + assert_matches_type(GPUBaremetalFlavorList, flavor, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.flavors.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = response.parse() + assert_matches_type(GPUBaremetalFlavorList, flavor, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.flavors.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = response.parse() + assert_matches_type(GPUBaremetalFlavorList, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncFlavors: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.gpu_baremetal.clusters.flavors.list( + project_id=1, + region_id=7, + ) + assert_matches_type(GPUBaremetalFlavorList, flavor, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.gpu_baremetal.clusters.flavors.list( + project_id=1, + region_id=7, + hide_disabled=True, + include_prices=True, + ) + assert_matches_type(GPUBaremetalFlavorList, flavor, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.flavors.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = await response.parse() + assert_matches_type(GPUBaremetalFlavorList, flavor, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.flavors.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = await response.parse() + assert_matches_type(GPUBaremetalFlavorList, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/gpu_baremetal/clusters/test_images.py b/tests/api_resources/cloud/gpu_baremetal/clusters/test_images.py new file mode 100644 index 00000000..3657deea --- /dev/null +++ b/tests/api_resources/cloud/gpu_baremetal/clusters/test_images.py @@ -0,0 +1,392 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import GPUImage, TaskIDList, GPUImageList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestImages: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + image = client.cloud.gpu_baremetal.clusters.images.list( + project_id=1, + region_id=7, + ) + assert_matches_type(GPUImageList, image, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.images.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(GPUImageList, image, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.images.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(GPUImageList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + image = client.cloud.gpu_baremetal.clusters.images.delete( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.images.with_raw_response.delete( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.images.with_streaming_response.delete( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + client.cloud.gpu_baremetal.clusters.images.with_raw_response.delete( + image_id="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + image = client.cloud.gpu_baremetal.clusters.images.get( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUImage, image, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.images.with_raw_response.get( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(GPUImage, image, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.images.with_streaming_response.get( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(GPUImage, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + client.cloud.gpu_baremetal.clusters.images.with_raw_response.get( + image_id="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_upload(self, client: Gcore) -> None: + image = client.cloud.gpu_baremetal.clusters.images.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_method_upload_with_all_params(self, client: Gcore) -> None: + image = client.cloud.gpu_baremetal.clusters.images.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + architecture="x86_64", + cow_format=True, + hw_firmware_type="bios", + os_distro="os_distro", + os_type="linux", + os_version="19.04", + ssh_key="allow", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_raw_response_upload(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.images.with_raw_response.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_streaming_response_upload(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.images.with_streaming_response.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncImages: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.gpu_baremetal.clusters.images.list( + project_id=1, + region_id=7, + ) + assert_matches_type(GPUImageList, image, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.images.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(GPUImageList, image, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.images.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(GPUImageList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.gpu_baremetal.clusters.images.delete( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.images.with_raw_response.delete( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.images.with_streaming_response.delete( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.images.with_raw_response.delete( + image_id="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.gpu_baremetal.clusters.images.get( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUImage, image, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.images.with_raw_response.get( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(GPUImage, image, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.images.with_streaming_response.get( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(GPUImage, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.images.with_raw_response.get( + image_id="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_upload(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.gpu_baremetal.clusters.images.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_method_upload_with_all_params(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.gpu_baremetal.clusters.images.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + architecture="x86_64", + cow_format=True, + hw_firmware_type="bios", + os_distro="os_distro", + os_type="linux", + os_version="19.04", + ssh_key="allow", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_raw_response_upload(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.images.with_raw_response.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_streaming_response_upload(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.images.with_streaming_response.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/gpu_baremetal/clusters/test_interfaces.py b/tests/api_resources/cloud/gpu_baremetal/clusters/test_interfaces.py new file mode 100644 index 00000000..de330f4d --- /dev/null +++ b/tests/api_resources/cloud/gpu_baremetal/clusters/test_interfaces.py @@ -0,0 +1,850 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import TaskIDList, NetworkInterfaceList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestInterfaces: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + interface = client.cloud.gpu_baremetal.clusters.interfaces.list( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) + assert_matches_type(NetworkInterfaceList, interface, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.list( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = response.parse() + assert_matches_type(NetworkInterfaceList, interface, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.interfaces.with_streaming_response.list( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = response.parse() + assert_matches_type(NetworkInterfaceList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.list( + cluster_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_attach_overload_1(self, client: Gcore) -> None: + interface = client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_method_attach_with_all_params_overload_1(self, client: Gcore) -> None: + interface = client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="interface_name", + ip_family="dual", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="external", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_raw_response_attach_overload_1(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_streaming_response_attach_overload_1(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_attach_overload_1(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_attach_overload_2(self, client: Gcore) -> None: + interface = client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_method_attach_with_all_params_overload_2(self, client: Gcore) -> None: + interface = client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="my-subnet-interface", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="subnet", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_raw_response_attach_overload_2(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_streaming_response_attach_overload_2(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_attach_overload_2(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + @parametrize + def test_method_attach_overload_3(self, client: Gcore) -> None: + interface = client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_method_attach_with_all_params_overload_3(self, client: Gcore) -> None: + interface = client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="my-any-subnet-interface", + ip_family="dual", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="any_subnet", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_raw_response_attach_overload_3(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_streaming_response_attach_overload_3(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_attach_overload_3(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + @parametrize + def test_method_attach_overload_4(self, client: Gcore) -> None: + interface = client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_method_attach_with_all_params_overload_4(self, client: Gcore) -> None: + interface = client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="my-rfip-interface", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="reserved_fixed_ip", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_raw_response_attach_overload_4(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_streaming_response_attach_overload_4(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_attach_overload_4(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) + + @parametrize + def test_method_detach(self, client: Gcore) -> None: + interface = client.cloud.gpu_baremetal.clusters.interfaces.detach( + instance_id="instance_id", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_raw_response_detach(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.detach( + instance_id="instance_id", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_streaming_response_detach(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.interfaces.with_streaming_response.detach( + instance_id="instance_id", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_detach(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.detach( + instance_id="", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) + + +class TestAsyncInterfaces: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.gpu_baremetal.clusters.interfaces.list( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) + assert_matches_type(NetworkInterfaceList, interface, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.list( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = await response.parse() + assert_matches_type(NetworkInterfaceList, interface, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.interfaces.with_streaming_response.list( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = await response.parse() + assert_matches_type(NetworkInterfaceList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.list( + cluster_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_attach_overload_1(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_method_attach_with_all_params_overload_1(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="interface_name", + ip_family="dual", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="external", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_raw_response_attach_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_streaming_response_attach_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_attach_overload_1(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_attach_overload_2(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_method_attach_with_all_params_overload_2(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="my-subnet-interface", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="subnet", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_raw_response_attach_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_streaming_response_attach_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_attach_overload_2(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + @parametrize + async def test_method_attach_overload_3(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_method_attach_with_all_params_overload_3(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="my-any-subnet-interface", + ip_family="dual", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="any_subnet", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_raw_response_attach_overload_3(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_streaming_response_attach_overload_3(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_attach_overload_3(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + @parametrize + async def test_method_attach_overload_4(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_method_attach_with_all_params_overload_4(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.gpu_baremetal.clusters.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="my-rfip-interface", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="reserved_fixed_ip", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_raw_response_attach_overload_4(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_streaming_response_attach_overload_4(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_attach_overload_4(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) + + @parametrize + async def test_method_detach(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.gpu_baremetal.clusters.interfaces.detach( + instance_id="instance_id", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_raw_response_detach(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.detach( + instance_id="instance_id", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_streaming_response_detach(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.interfaces.with_streaming_response.detach( + instance_id="instance_id", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_detach(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.interfaces.with_raw_response.detach( + instance_id="", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) diff --git a/tests/api_resources/cloud/gpu_baremetal/clusters/test_servers.py b/tests/api_resources/cloud/gpu_baremetal/clusters/test_servers.py new file mode 100644 index 00000000..d468d7c4 --- /dev/null +++ b/tests/api_resources/cloud/gpu_baremetal/clusters/test_servers.py @@ -0,0 +1,572 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import Console, TaskIDList +from gcore.types.cloud.gpu_baremetal.clusters import ( + GPUBaremetalClusterServer, + GPUBaremetalClusterServerV1, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestServers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + server = client.cloud.gpu_baremetal.clusters.servers.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(SyncOffsetPage[GPUBaremetalClusterServer], server, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + server = client.cloud.gpu_baremetal.clusters.servers.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + changed_before=parse_datetime("2025-10-01T12:00:00Z"), + changed_since=parse_datetime("2025-10-01T12:00:00Z"), + ip_address="237.84.2.178", + limit=10, + name="name", + offset=0, + order_by="created_at.asc", + status="ACTIVE", + uuids=["string"], + ) + assert_matches_type(SyncOffsetPage[GPUBaremetalClusterServer], server, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.servers.with_raw_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = response.parse() + assert_matches_type(SyncOffsetPage[GPUBaremetalClusterServer], server, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.servers.with_streaming_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = response.parse() + assert_matches_type(SyncOffsetPage[GPUBaremetalClusterServer], server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_baremetal.clusters.servers.with_raw_response.list( + cluster_id="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + server = client.cloud.gpu_baremetal.clusters.servers.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_id="cluster_id", + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_method_delete_with_all_params(self, client: Gcore) -> None: + server = client.cloud.gpu_baremetal.clusters.servers.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_id="cluster_id", + delete_floatings=True, + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.servers.with_raw_response.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_id="cluster_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.servers.with_streaming_response.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_id="cluster_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_baremetal.clusters.servers.with_raw_response.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.gpu_baremetal.clusters.servers.with_raw_response.delete( + instance_id="", + project_id=0, + region_id=0, + cluster_id="cluster_id", + ) + + @parametrize + def test_method_get_console(self, client: Gcore) -> None: + server = client.cloud.gpu_baremetal.clusters.servers.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Console, server, path=["response"]) + + @parametrize + def test_raw_response_get_console(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.servers.with_raw_response.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = response.parse() + assert_matches_type(Console, server, path=["response"]) + + @parametrize + def test_streaming_response_get_console(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.servers.with_streaming_response.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = response.parse() + assert_matches_type(Console, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_console(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.gpu_baremetal.clusters.servers.with_raw_response.get_console( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_powercycle(self, client: Gcore) -> None: + server = client.cloud.gpu_baremetal.clusters.servers.powercycle( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) + + @parametrize + def test_raw_response_powercycle(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.servers.with_raw_response.powercycle( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = response.parse() + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) + + @parametrize + def test_streaming_response_powercycle(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.servers.with_streaming_response.powercycle( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = response.parse() + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_powercycle(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.gpu_baremetal.clusters.servers.with_raw_response.powercycle( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_reboot(self, client: Gcore) -> None: + server = client.cloud.gpu_baremetal.clusters.servers.reboot( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) + + @parametrize + def test_raw_response_reboot(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.servers.with_raw_response.reboot( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = response.parse() + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) + + @parametrize + def test_streaming_response_reboot(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.servers.with_streaming_response.reboot( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = response.parse() + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_reboot(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.gpu_baremetal.clusters.servers.with_raw_response.reboot( + instance_id="", + project_id=0, + region_id=0, + ) + + +class TestAsyncServers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.gpu_baremetal.clusters.servers.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(AsyncOffsetPage[GPUBaremetalClusterServer], server, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.gpu_baremetal.clusters.servers.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + changed_before=parse_datetime("2025-10-01T12:00:00Z"), + changed_since=parse_datetime("2025-10-01T12:00:00Z"), + ip_address="237.84.2.178", + limit=10, + name="name", + offset=0, + order_by="created_at.asc", + status="ACTIVE", + uuids=["string"], + ) + assert_matches_type(AsyncOffsetPage[GPUBaremetalClusterServer], server, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = await response.parse() + assert_matches_type(AsyncOffsetPage[GPUBaremetalClusterServer], server, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.servers.with_streaming_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = await response.parse() + assert_matches_type(AsyncOffsetPage[GPUBaremetalClusterServer], server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.list( + cluster_id="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.gpu_baremetal.clusters.servers.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_id="cluster_id", + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.gpu_baremetal.clusters.servers.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_id="cluster_id", + delete_floatings=True, + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_id="cluster_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = await response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.servers.with_streaming_response.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_id="cluster_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = await response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.delete( + instance_id="", + project_id=0, + region_id=0, + cluster_id="cluster_id", + ) + + @parametrize + async def test_method_get_console(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.gpu_baremetal.clusters.servers.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Console, server, path=["response"]) + + @parametrize + async def test_raw_response_get_console(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = await response.parse() + assert_matches_type(Console, server, path=["response"]) + + @parametrize + async def test_streaming_response_get_console(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.servers.with_streaming_response.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = await response.parse() + assert_matches_type(Console, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_console(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.get_console( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_powercycle(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.gpu_baremetal.clusters.servers.powercycle( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) + + @parametrize + async def test_raw_response_powercycle(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.powercycle( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = await response.parse() + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) + + @parametrize + async def test_streaming_response_powercycle(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.servers.with_streaming_response.powercycle( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = await response.parse() + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_powercycle(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.powercycle( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_reboot(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.gpu_baremetal.clusters.servers.reboot( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) + + @parametrize + async def test_raw_response_reboot(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.reboot( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = await response.parse() + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) + + @parametrize + async def test_streaming_response_reboot(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.servers.with_streaming_response.reboot( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = await response.parse() + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_reboot(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.servers.with_raw_response.reboot( + instance_id="", + project_id=0, + region_id=0, + ) diff --git a/tests/api_resources/cloud/gpu_baremetal/test_clusters.py b/tests/api_resources/cloud/gpu_baremetal/test_clusters.py new file mode 100644 index 00000000..3a47eba9 --- /dev/null +++ b/tests/api_resources/cloud/gpu_baremetal/test_clusters.py @@ -0,0 +1,1013 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import TaskIDList +from gcore.types.cloud.gpu_baremetal import ( + GPUBaremetalCluster, +) +from gcore.types.cloud.gpu_baremetal.clusters import GPUBaremetalClusterServerV1List + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestClusters: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + image_id="3793c250-0b3b-4678-bab3-e11afbc29657", + name="gpu-cluster-1", + servers_count=3, + servers_settings={"interfaces": [{"type": "external"}]}, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + image_id="3793c250-0b3b-4678-bab3-e11afbc29657", + name="gpu-cluster-1", + servers_count=3, + servers_settings={ + "interfaces": [ + { + "type": "external", + "ip_family": "ipv4", + "name": "eth0", + } + ], + "credentials": { + "password": "securepassword", + "ssh_key_name": "my-ssh-key", + "username": "admin", + }, + "file_shares": [ + { + "id": "a3f2d1b8-45e6-4f8a-bb5d-19dbf2cd7e9a", + "mount_path": "/mnt/vast", + } + ], + "security_groups": [{"id": "b4849ffa-89f2-45a1-951f-0ae5b7809d98"}], + "user_data": "eyJ0ZXN0IjogImRhdGEifQ==", + }, + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.with_raw_response.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + image_id="3793c250-0b3b-4678-bab3-e11afbc29657", + name="gpu-cluster-1", + servers_count=3, + servers_settings={"interfaces": [{"type": "external"}]}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.with_streaming_response.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + image_id="3793c250-0b3b-4678-bab3-e11afbc29657", + name="gpu-cluster-1", + servers_count=3, + servers_settings={"interfaces": [{"type": "external"}]}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.list( + project_id=1, + region_id=7, + ) + assert_matches_type(SyncOffsetPage[GPUBaremetalCluster], cluster, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.list( + project_id=1, + region_id=7, + limit=10, + managed_by=["k8s"], + offset=0, + ) + assert_matches_type(SyncOffsetPage[GPUBaremetalCluster], cluster, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(SyncOffsetPage[GPUBaremetalCluster], cluster, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(SyncOffsetPage[GPUBaremetalCluster], cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_method_delete_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + all_floating_ips=True, + all_reserved_fixed_ips=True, + floating_ip_ids=["e4a01208-d6ac-4304-bf86-3028154b070a"], + reserved_fixed_ip_ids=["a29b8e1e-08d3-4cec-91fb-06e81e5f46d5"], + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.with_raw_response.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.with_streaming_response.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_baremetal.clusters.with_raw_response.delete( + cluster_id="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_action(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_action(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_action(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_action(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_baremetal.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.get( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.with_raw_response.get( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.with_streaming_response.get( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_baremetal.clusters.with_raw_response.get( + cluster_id="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_powercycle_all_servers(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.powercycle_all_servers( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) + assert_matches_type(GPUBaremetalClusterServerV1List, cluster, path=["response"]) + + @parametrize + def test_raw_response_powercycle_all_servers(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.with_raw_response.powercycle_all_servers( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(GPUBaremetalClusterServerV1List, cluster, path=["response"]) + + @parametrize + def test_streaming_response_powercycle_all_servers(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.with_streaming_response.powercycle_all_servers( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(GPUBaremetalClusterServerV1List, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_powercycle_all_servers(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_baremetal.clusters.with_raw_response.powercycle_all_servers( + cluster_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_reboot_all_servers(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.reboot_all_servers( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) + assert_matches_type(GPUBaremetalClusterServerV1List, cluster, path=["response"]) + + @parametrize + def test_raw_response_reboot_all_servers(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.with_raw_response.reboot_all_servers( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(GPUBaremetalClusterServerV1List, cluster, path=["response"]) + + @parametrize + def test_streaming_response_reboot_all_servers(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.with_streaming_response.reboot_all_servers( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(GPUBaremetalClusterServerV1List, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_reboot_all_servers(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_baremetal.clusters.with_raw_response.reboot_all_servers( + cluster_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_rebuild(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.rebuild( + cluster_id="cluster_id", + project_id=0, + region_id=0, + nodes=["string"], + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_method_rebuild_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.rebuild( + cluster_id="cluster_id", + project_id=0, + region_id=0, + nodes=["string"], + image_id="f01fd9a0-9548-48ba-82dc-a8c8b2d6f2f1", + user_data="user_data", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_rebuild(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.with_raw_response.rebuild( + cluster_id="cluster_id", + project_id=0, + region_id=0, + nodes=["string"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_rebuild(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.with_streaming_response.rebuild( + cluster_id="cluster_id", + project_id=0, + region_id=0, + nodes=["string"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_rebuild(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_baremetal.clusters.with_raw_response.rebuild( + cluster_id="", + project_id=0, + region_id=0, + nodes=["string"], + ) + + @parametrize + def test_method_resize(self, client: Gcore) -> None: + cluster = client.cloud.gpu_baremetal.clusters.resize( + cluster_id="cluster_id", + project_id=0, + region_id=0, + instances_count=1, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_resize(self, client: Gcore) -> None: + response = client.cloud.gpu_baremetal.clusters.with_raw_response.resize( + cluster_id="cluster_id", + project_id=0, + region_id=0, + instances_count=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_resize(self, client: Gcore) -> None: + with client.cloud.gpu_baremetal.clusters.with_streaming_response.resize( + cluster_id="cluster_id", + project_id=0, + region_id=0, + instances_count=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_resize(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_baremetal.clusters.with_raw_response.resize( + cluster_id="", + project_id=0, + region_id=0, + instances_count=1, + ) + + +class TestAsyncClusters: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + image_id="3793c250-0b3b-4678-bab3-e11afbc29657", + name="gpu-cluster-1", + servers_count=3, + servers_settings={"interfaces": [{"type": "external"}]}, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + image_id="3793c250-0b3b-4678-bab3-e11afbc29657", + name="gpu-cluster-1", + servers_count=3, + servers_settings={ + "interfaces": [ + { + "type": "external", + "ip_family": "ipv4", + "name": "eth0", + } + ], + "credentials": { + "password": "securepassword", + "ssh_key_name": "my-ssh-key", + "username": "admin", + }, + "file_shares": [ + { + "id": "a3f2d1b8-45e6-4f8a-bb5d-19dbf2cd7e9a", + "mount_path": "/mnt/vast", + } + ], + "security_groups": [{"id": "b4849ffa-89f2-45a1-951f-0ae5b7809d98"}], + "user_data": "eyJ0ZXN0IjogImRhdGEifQ==", + }, + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.with_raw_response.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + image_id="3793c250-0b3b-4678-bab3-e11afbc29657", + name="gpu-cluster-1", + servers_count=3, + servers_settings={"interfaces": [{"type": "external"}]}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.with_streaming_response.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + image_id="3793c250-0b3b-4678-bab3-e11afbc29657", + name="gpu-cluster-1", + servers_count=3, + servers_settings={"interfaces": [{"type": "external"}]}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.list( + project_id=1, + region_id=7, + ) + assert_matches_type(AsyncOffsetPage[GPUBaremetalCluster], cluster, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.list( + project_id=1, + region_id=7, + limit=10, + managed_by=["k8s"], + offset=0, + ) + assert_matches_type(AsyncOffsetPage[GPUBaremetalCluster], cluster, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(AsyncOffsetPage[GPUBaremetalCluster], cluster, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(AsyncOffsetPage[GPUBaremetalCluster], cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + all_floating_ips=True, + all_reserved_fixed_ips=True, + floating_ip_ids=["e4a01208-d6ac-4304-bf86-3028154b070a"], + reserved_fixed_ip_ids=["a29b8e1e-08d3-4cec-91fb-06e81e5f46d5"], + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.with_raw_response.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.with_streaming_response.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.with_raw_response.delete( + cluster_id="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_action(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_action(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_action(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_action(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.get( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.with_raw_response.get( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.with_streaming_response.get( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(GPUBaremetalCluster, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.with_raw_response.get( + cluster_id="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_powercycle_all_servers(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.powercycle_all_servers( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) + assert_matches_type(GPUBaremetalClusterServerV1List, cluster, path=["response"]) + + @parametrize + async def test_raw_response_powercycle_all_servers(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.with_raw_response.powercycle_all_servers( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(GPUBaremetalClusterServerV1List, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_powercycle_all_servers(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.with_streaming_response.powercycle_all_servers( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(GPUBaremetalClusterServerV1List, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_powercycle_all_servers(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.with_raw_response.powercycle_all_servers( + cluster_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_reboot_all_servers(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.reboot_all_servers( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) + assert_matches_type(GPUBaremetalClusterServerV1List, cluster, path=["response"]) + + @parametrize + async def test_raw_response_reboot_all_servers(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.with_raw_response.reboot_all_servers( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(GPUBaremetalClusterServerV1List, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_reboot_all_servers(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.with_streaming_response.reboot_all_servers( + cluster_id="cluster_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(GPUBaremetalClusterServerV1List, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_reboot_all_servers(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.with_raw_response.reboot_all_servers( + cluster_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_rebuild(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.rebuild( + cluster_id="cluster_id", + project_id=0, + region_id=0, + nodes=["string"], + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_method_rebuild_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.rebuild( + cluster_id="cluster_id", + project_id=0, + region_id=0, + nodes=["string"], + image_id="f01fd9a0-9548-48ba-82dc-a8c8b2d6f2f1", + user_data="user_data", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_rebuild(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.with_raw_response.rebuild( + cluster_id="cluster_id", + project_id=0, + region_id=0, + nodes=["string"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_rebuild(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.with_streaming_response.rebuild( + cluster_id="cluster_id", + project_id=0, + region_id=0, + nodes=["string"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_rebuild(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.with_raw_response.rebuild( + cluster_id="", + project_id=0, + region_id=0, + nodes=["string"], + ) + + @parametrize + async def test_method_resize(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_baremetal.clusters.resize( + cluster_id="cluster_id", + project_id=0, + region_id=0, + instances_count=1, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_resize(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_baremetal.clusters.with_raw_response.resize( + cluster_id="cluster_id", + project_id=0, + region_id=0, + instances_count=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_resize(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_baremetal.clusters.with_streaming_response.resize( + cluster_id="cluster_id", + project_id=0, + region_id=0, + instances_count=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_resize(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_baremetal.clusters.with_raw_response.resize( + cluster_id="", + project_id=0, + region_id=0, + instances_count=1, + ) diff --git a/tests/api_resources/cloud/gpu_virtual/__init__.py b/tests/api_resources/cloud/gpu_virtual/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/gpu_virtual/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/gpu_virtual/clusters/__init__.py b/tests/api_resources/cloud/gpu_virtual/clusters/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/gpu_virtual/clusters/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/gpu_virtual/clusters/test_flavors.py b/tests/api_resources/cloud/gpu_virtual/clusters/test_flavors.py new file mode 100644 index 00000000..4f1118ae --- /dev/null +++ b/tests/api_resources/cloud/gpu_virtual/clusters/test_flavors.py @@ -0,0 +1,112 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.gpu_virtual.clusters import GPUVirtualFlavorList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFlavors: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + flavor = client.cloud.gpu_virtual.clusters.flavors.list( + project_id=1, + region_id=7, + ) + assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + flavor = client.cloud.gpu_virtual.clusters.flavors.list( + project_id=1, + region_id=7, + hide_disabled=True, + include_prices=True, + ) + assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.flavors.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = response.parse() + assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.flavors.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = response.parse() + assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncFlavors: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.gpu_virtual.clusters.flavors.list( + project_id=1, + region_id=7, + ) + assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.gpu_virtual.clusters.flavors.list( + project_id=1, + region_id=7, + hide_disabled=True, + include_prices=True, + ) + assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.flavors.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = await response.parse() + assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.flavors.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = await response.parse() + assert_matches_type(GPUVirtualFlavorList, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/gpu_virtual/clusters/test_images.py b/tests/api_resources/cloud/gpu_virtual/clusters/test_images.py new file mode 100644 index 00000000..669aa6c0 --- /dev/null +++ b/tests/api_resources/cloud/gpu_virtual/clusters/test_images.py @@ -0,0 +1,392 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import GPUImage, TaskIDList, GPUImageList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestImages: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + image = client.cloud.gpu_virtual.clusters.images.list( + project_id=1, + region_id=7, + ) + assert_matches_type(GPUImageList, image, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.images.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(GPUImageList, image, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.images.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(GPUImageList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + image = client.cloud.gpu_virtual.clusters.images.delete( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.images.with_raw_response.delete( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.images.with_streaming_response.delete( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + client.cloud.gpu_virtual.clusters.images.with_raw_response.delete( + image_id="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + image = client.cloud.gpu_virtual.clusters.images.get( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUImage, image, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.images.with_raw_response.get( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(GPUImage, image, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.images.with_streaming_response.get( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(GPUImage, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + client.cloud.gpu_virtual.clusters.images.with_raw_response.get( + image_id="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_upload(self, client: Gcore) -> None: + image = client.cloud.gpu_virtual.clusters.images.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_method_upload_with_all_params(self, client: Gcore) -> None: + image = client.cloud.gpu_virtual.clusters.images.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + architecture="x86_64", + cow_format=True, + hw_firmware_type="bios", + os_distro="os_distro", + os_type="linux", + os_version="19.04", + ssh_key="allow", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_raw_response_upload(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.images.with_raw_response.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_streaming_response_upload(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.images.with_streaming_response.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncImages: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.gpu_virtual.clusters.images.list( + project_id=1, + region_id=7, + ) + assert_matches_type(GPUImageList, image, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.images.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(GPUImageList, image, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.images.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(GPUImageList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.gpu_virtual.clusters.images.delete( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.images.with_raw_response.delete( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.images.with_streaming_response.delete( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.images.with_raw_response.delete( + image_id="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.gpu_virtual.clusters.images.get( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUImage, image, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.images.with_raw_response.get( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(GPUImage, image, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.images.with_streaming_response.get( + image_id="8cab6f28-09ca-4201-b3f7-23c7893f4bd6", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(GPUImage, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.images.with_raw_response.get( + image_id="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_upload(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.gpu_virtual.clusters.images.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_method_upload_with_all_params(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.gpu_virtual.clusters.images.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + architecture="x86_64", + cow_format=True, + hw_firmware_type="bios", + os_distro="os_distro", + os_type="linux", + os_version="19.04", + ssh_key="allow", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_raw_response_upload(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.images.with_raw_response.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_streaming_response_upload(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.images.with_streaming_response.upload( + project_id=1, + region_id=7, + name="ubuntu-23.10-x64", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/gpu_virtual/clusters/test_interfaces.py b/tests/api_resources/cloud/gpu_virtual/clusters/test_interfaces.py new file mode 100644 index 00000000..b2cbbb85 --- /dev/null +++ b/tests/api_resources/cloud/gpu_virtual/clusters/test_interfaces.py @@ -0,0 +1,116 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.gpu_virtual.clusters import GPUVirtualInterfaceList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestInterfaces: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + interface = client.cloud.gpu_virtual.clusters.interfaces.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUVirtualInterfaceList, interface, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.interfaces.with_raw_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = response.parse() + assert_matches_type(GPUVirtualInterfaceList, interface, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.interfaces.with_streaming_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = response.parse() + assert_matches_type(GPUVirtualInterfaceList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_virtual.clusters.interfaces.with_raw_response.list( + cluster_id="", + project_id=1, + region_id=7, + ) + + +class TestAsyncInterfaces: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.gpu_virtual.clusters.interfaces.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUVirtualInterfaceList, interface, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.interfaces.with_raw_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = await response.parse() + assert_matches_type(GPUVirtualInterfaceList, interface, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.interfaces.with_streaming_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = await response.parse() + assert_matches_type(GPUVirtualInterfaceList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.interfaces.with_raw_response.list( + cluster_id="", + project_id=1, + region_id=7, + ) diff --git a/tests/api_resources/cloud/gpu_virtual/clusters/test_servers.py b/tests/api_resources/cloud/gpu_virtual/clusters/test_servers.py new file mode 100644 index 00000000..29ca8dc8 --- /dev/null +++ b/tests/api_resources/cloud/gpu_virtual/clusters/test_servers.py @@ -0,0 +1,302 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.types.cloud import TaskIDList +from gcore.types.cloud.gpu_virtual.clusters import GPUVirtualClusterServerList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestServers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + server = client.cloud.gpu_virtual.clusters.servers.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUVirtualClusterServerList, server, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + server = client.cloud.gpu_virtual.clusters.servers.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + changed_before=parse_datetime("2025-10-01T12:00:00Z"), + changed_since=parse_datetime("2025-10-01T12:00:00Z"), + ip_address="237.84.2.178", + limit=10, + name="name", + offset=0, + order_by="created_at.asc", + status="ACTIVE", + uuids=["string"], + ) + assert_matches_type(GPUVirtualClusterServerList, server, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.servers.with_raw_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = response.parse() + assert_matches_type(GPUVirtualClusterServerList, server, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.servers.with_streaming_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = response.parse() + assert_matches_type(GPUVirtualClusterServerList, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_virtual.clusters.servers.with_raw_response.list( + cluster_id="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + server = client.cloud.gpu_virtual.clusters.servers.delete( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_method_delete_with_all_params(self, client: Gcore) -> None: + server = client.cloud.gpu_virtual.clusters.servers.delete( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + all_floating_ips=True, + all_reserved_fixed_ips=True, + all_volumes=True, + floating_ip_ids=["e4a01208-d6ac-4304-bf86-3028154b070a"], + reserved_fixed_ip_ids=["a29b8e1e-08d3-4cec-91fb-06e81e5f46d5"], + volume_ids=["1333c684-c3da-4b91-ac9e-a92706aa2824"], + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.servers.with_raw_response.delete( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.servers.with_streaming_response.delete( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_virtual.clusters.servers.with_raw_response.delete( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `server_id` but received ''"): + client.cloud.gpu_virtual.clusters.servers.with_raw_response.delete( + server_id="", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) + + +class TestAsyncServers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.gpu_virtual.clusters.servers.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUVirtualClusterServerList, server, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.gpu_virtual.clusters.servers.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + changed_before=parse_datetime("2025-10-01T12:00:00Z"), + changed_since=parse_datetime("2025-10-01T12:00:00Z"), + ip_address="237.84.2.178", + limit=10, + name="name", + offset=0, + order_by="created_at.asc", + status="ACTIVE", + uuids=["string"], + ) + assert_matches_type(GPUVirtualClusterServerList, server, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.servers.with_raw_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = await response.parse() + assert_matches_type(GPUVirtualClusterServerList, server, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.servers.with_streaming_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = await response.parse() + assert_matches_type(GPUVirtualClusterServerList, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.servers.with_raw_response.list( + cluster_id="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.gpu_virtual.clusters.servers.delete( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGcore) -> None: + server = await async_client.cloud.gpu_virtual.clusters.servers.delete( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + all_floating_ips=True, + all_reserved_fixed_ips=True, + all_volumes=True, + floating_ip_ids=["e4a01208-d6ac-4304-bf86-3028154b070a"], + reserved_fixed_ip_ids=["a29b8e1e-08d3-4cec-91fb-06e81e5f46d5"], + volume_ids=["1333c684-c3da-4b91-ac9e-a92706aa2824"], + ) + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.servers.with_raw_response.delete( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + server = await response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.servers.with_streaming_response.delete( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + server = await response.parse() + assert_matches_type(TaskIDList, server, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.servers.with_raw_response.delete( + server_id="f1c1eeb6-1834-48c9-a7b0-daafce64872b", + project_id=1, + region_id=7, + cluster_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `server_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.servers.with_raw_response.delete( + server_id="", + project_id=1, + region_id=7, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + ) diff --git a/tests/api_resources/cloud/gpu_virtual/clusters/test_volumes.py b/tests/api_resources/cloud/gpu_virtual/clusters/test_volumes.py new file mode 100644 index 00000000..37d10355 --- /dev/null +++ b/tests/api_resources/cloud/gpu_virtual/clusters/test_volumes.py @@ -0,0 +1,116 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.gpu_virtual.clusters import GPUVirtualClusterVolumeList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestVolumes: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + volume = client.cloud.gpu_virtual.clusters.volumes.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUVirtualClusterVolumeList, volume, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.volumes.with_raw_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(GPUVirtualClusterVolumeList, volume, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.volumes.with_streaming_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert_matches_type(GPUVirtualClusterVolumeList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_virtual.clusters.volumes.with_raw_response.list( + cluster_id="", + project_id=1, + region_id=7, + ) + + +class TestAsyncVolumes: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.gpu_virtual.clusters.volumes.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUVirtualClusterVolumeList, volume, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.volumes.with_raw_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = await response.parse() + assert_matches_type(GPUVirtualClusterVolumeList, volume, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.volumes.with_streaming_response.list( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert_matches_type(GPUVirtualClusterVolumeList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.volumes.with_raw_response.list( + cluster_id="", + project_id=1, + region_id=7, + ) diff --git a/tests/api_resources/cloud/gpu_virtual/test_clusters.py b/tests/api_resources/cloud/gpu_virtual/test_clusters.py new file mode 100644 index 00000000..0487f803 --- /dev/null +++ b/tests/api_resources/cloud/gpu_virtual/test_clusters.py @@ -0,0 +1,1294 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import TaskIDList +from gcore.types.cloud.gpu_virtual import ( + GPUVirtualCluster, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestClusters: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + name="gpu-cluster-1", + servers_count=3, + servers_settings={ + "interfaces": [{"type": "external"}], + "volumes": [ + { + "boot_index": 1, + "name": "my-data-disk", + "size": 100, + "source": "new", + "type": "cold", + } + ], + }, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + name="gpu-cluster-1", + servers_count=3, + servers_settings={ + "interfaces": [ + { + "type": "external", + "ip_family": "ipv4", + "name": "eth0", + } + ], + "volumes": [ + { + "boot_index": 1, + "name": "my-data-disk", + "size": 100, + "source": "new", + "type": "cold", + "delete_on_termination": True, + "tags": {"key1": "value1"}, + } + ], + "credentials": { + "password": "securepassword", + "ssh_key_name": "my-ssh-key", + "username": "admin", + }, + "file_shares": [ + { + "id": "a3f2d1b8-45e6-4f8a-bb5d-19dbf2cd7e9a", + "mount_path": "/mnt/vast", + } + ], + "security_groups": [{"id": "b4849ffa-89f2-45a1-951f-0ae5b7809d98"}], + "user_data": "eyJ0ZXN0IjogImRhdGEifQ==", + }, + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.with_raw_response.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + name="gpu-cluster-1", + servers_count=3, + servers_settings={ + "interfaces": [{"type": "external"}], + "volumes": [ + { + "boot_index": 1, + "name": "my-data-disk", + "size": 100, + "source": "new", + "type": "cold", + } + ], + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.with_streaming_response.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + name="gpu-cluster-1", + servers_count=3, + servers_settings={ + "interfaces": [{"type": "external"}], + "volumes": [ + { + "boot_index": 1, + "name": "my-data-disk", + "size": 100, + "source": "new", + "type": "cold", + } + ], + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.update( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + name="gpu-cluster-1", + ) + assert_matches_type(GPUVirtualCluster, cluster, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.with_raw_response.update( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + name="gpu-cluster-1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(GPUVirtualCluster, cluster, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.with_streaming_response.update( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + name="gpu-cluster-1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(GPUVirtualCluster, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_virtual.clusters.with_raw_response.update( + cluster_id="", + project_id=1, + region_id=7, + name="gpu-cluster-1", + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.list( + project_id=1, + region_id=7, + ) + assert_matches_type(SyncOffsetPage[GPUVirtualCluster], cluster, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.list( + project_id=1, + region_id=7, + limit=10, + offset=0, + ) + assert_matches_type(SyncOffsetPage[GPUVirtualCluster], cluster, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(SyncOffsetPage[GPUVirtualCluster], cluster, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(SyncOffsetPage[GPUVirtualCluster], cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_method_delete_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + all_floating_ips=True, + all_reserved_fixed_ips=True, + all_volumes=True, + floating_ip_ids=["e4a01208-d6ac-4304-bf86-3028154b070a"], + reserved_fixed_ip_ids=["a29b8e1e-08d3-4cec-91fb-06e81e5f46d5"], + volume_ids=["1333c684-c3da-4b91-ac9e-a92706aa2824"], + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.with_raw_response.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.with_streaming_response.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_virtual.clusters.with_raw_response.delete( + cluster_id="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_action_overload_1(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="start", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_action_overload_1(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="start", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_action_overload_1(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="start", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_action_overload_1(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="start", + ) + + @parametrize + def test_method_action_overload_2(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="stop", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_action_overload_2(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="stop", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_action_overload_2(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="stop", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_action_overload_2(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="stop", + ) + + @parametrize + def test_method_action_overload_3(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="soft_reboot", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_action_overload_3(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="soft_reboot", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_action_overload_3(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="soft_reboot", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_action_overload_3(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="soft_reboot", + ) + + @parametrize + def test_method_action_overload_4(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="hard_reboot", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_action_overload_4(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="hard_reboot", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_action_overload_4(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="hard_reboot", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_action_overload_4(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="hard_reboot", + ) + + @parametrize + def test_method_action_overload_5(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_action_overload_5(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_action_overload_5(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_action_overload_5(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) + + @parametrize + def test_method_action_overload_6(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="resize", + servers_count=5, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_action_overload_6(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="resize", + servers_count=5, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_action_overload_6(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="resize", + servers_count=5, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_action_overload_6(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="resize", + servers_count=5, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + cluster = client.cloud.gpu_virtual.clusters.get( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUVirtualCluster, cluster, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.gpu_virtual.clusters.with_raw_response.get( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(GPUVirtualCluster, cluster, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.gpu_virtual.clusters.with_streaming_response.get( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(GPUVirtualCluster, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + client.cloud.gpu_virtual.clusters.with_raw_response.get( + cluster_id="", + project_id=1, + region_id=7, + ) + + +class TestAsyncClusters: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + name="gpu-cluster-1", + servers_count=3, + servers_settings={ + "interfaces": [{"type": "external"}], + "volumes": [ + { + "boot_index": 1, + "name": "my-data-disk", + "size": 100, + "source": "new", + "type": "cold", + } + ], + }, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + name="gpu-cluster-1", + servers_count=3, + servers_settings={ + "interfaces": [ + { + "type": "external", + "ip_family": "ipv4", + "name": "eth0", + } + ], + "volumes": [ + { + "boot_index": 1, + "name": "my-data-disk", + "size": 100, + "source": "new", + "type": "cold", + "delete_on_termination": True, + "tags": {"key1": "value1"}, + } + ], + "credentials": { + "password": "securepassword", + "ssh_key_name": "my-ssh-key", + "username": "admin", + }, + "file_shares": [ + { + "id": "a3f2d1b8-45e6-4f8a-bb5d-19dbf2cd7e9a", + "mount_path": "/mnt/vast", + } + ], + "security_groups": [{"id": "b4849ffa-89f2-45a1-951f-0ae5b7809d98"}], + "user_data": "eyJ0ZXN0IjogImRhdGEifQ==", + }, + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.with_raw_response.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + name="gpu-cluster-1", + servers_count=3, + servers_settings={ + "interfaces": [{"type": "external"}], + "volumes": [ + { + "boot_index": 1, + "name": "my-data-disk", + "size": 100, + "source": "new", + "type": "cold", + } + ], + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.with_streaming_response.create( + project_id=1, + region_id=7, + flavor="g3-ai-32-192-1500-l40s-48-1", + name="gpu-cluster-1", + servers_count=3, + servers_settings={ + "interfaces": [{"type": "external"}], + "volumes": [ + { + "boot_index": 1, + "name": "my-data-disk", + "size": 100, + "source": "new", + "type": "cold", + } + ], + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.update( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + name="gpu-cluster-1", + ) + assert_matches_type(GPUVirtualCluster, cluster, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.with_raw_response.update( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + name="gpu-cluster-1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(GPUVirtualCluster, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.with_streaming_response.update( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + name="gpu-cluster-1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(GPUVirtualCluster, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.with_raw_response.update( + cluster_id="", + project_id=1, + region_id=7, + name="gpu-cluster-1", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.list( + project_id=1, + region_id=7, + ) + assert_matches_type(AsyncOffsetPage[GPUVirtualCluster], cluster, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.list( + project_id=1, + region_id=7, + limit=10, + offset=0, + ) + assert_matches_type(AsyncOffsetPage[GPUVirtualCluster], cluster, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(AsyncOffsetPage[GPUVirtualCluster], cluster, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(AsyncOffsetPage[GPUVirtualCluster], cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + all_floating_ips=True, + all_reserved_fixed_ips=True, + all_volumes=True, + floating_ip_ids=["e4a01208-d6ac-4304-bf86-3028154b070a"], + reserved_fixed_ip_ids=["a29b8e1e-08d3-4cec-91fb-06e81e5f46d5"], + volume_ids=["1333c684-c3da-4b91-ac9e-a92706aa2824"], + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.with_raw_response.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.with_streaming_response.delete( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.with_raw_response.delete( + cluster_id="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_action_overload_1(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="start", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_action_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="start", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_action_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="start", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_action_overload_1(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="start", + ) + + @parametrize + async def test_method_action_overload_2(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="stop", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_action_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="stop", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_action_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="stop", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_action_overload_2(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="stop", + ) + + @parametrize + async def test_method_action_overload_3(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="soft_reboot", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_action_overload_3(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="soft_reboot", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_action_overload_3(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="soft_reboot", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_action_overload_3(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="soft_reboot", + ) + + @parametrize + async def test_method_action_overload_4(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="hard_reboot", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_action_overload_4(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="hard_reboot", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_action_overload_4(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="hard_reboot", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_action_overload_4(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="hard_reboot", + ) + + @parametrize + async def test_method_action_overload_5(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_action_overload_5(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_action_overload_5(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_action_overload_5(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="update_tags", + tags={}, + ) + + @parametrize + async def test_method_action_overload_6(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="resize", + servers_count=5, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_action_overload_6(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="resize", + servers_count=5, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_action_overload_6(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.with_streaming_response.action( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + action="resize", + servers_count=5, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_action_overload_6(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.with_raw_response.action( + cluster_id="", + project_id=1, + region_id=7, + action="resize", + servers_count=5, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.gpu_virtual.clusters.get( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + assert_matches_type(GPUVirtualCluster, cluster, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.gpu_virtual.clusters.with_raw_response.get( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(GPUVirtualCluster, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.gpu_virtual.clusters.with_streaming_response.get( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(GPUVirtualCluster, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_id` but received ''"): + await async_client.cloud.gpu_virtual.clusters.with_raw_response.get( + cluster_id="", + project_id=1, + region_id=7, + ) diff --git a/tests/api_resources/cloud/inference/__init__.py b/tests/api_resources/cloud/inference/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/inference/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/inference/applications/__init__.py b/tests/api_resources/cloud/inference/applications/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/inference/applications/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/inference/applications/test_deployments.py b/tests/api_resources/cloud/inference/applications/test_deployments.py new file mode 100644 index 00000000..dd38dbe7 --- /dev/null +++ b/tests/api_resources/cloud/inference/applications/test_deployments.py @@ -0,0 +1,568 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import TaskIDList +from gcore.types.cloud.inference.applications import ( + InferenceApplicationDeployment, + InferenceApplicationDeploymentList, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDeployments: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + deployment = client.cloud.inference.applications.deployments.create( + project_id=1, + application_name="demo-app", + components_configuration={ + "model": { + "exposed": True, + "flavor": "inference-16vcpu-232gib-1xh100-80gb", + "scale": { + "max": 1, + "min": 1, + }, + } + }, + name="name", + regions=[1, 2], + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + deployment = client.cloud.inference.applications.deployments.create( + project_id=1, + application_name="demo-app", + components_configuration={ + "model": { + "exposed": True, + "flavor": "inference-16vcpu-232gib-1xh100-80gb", + "scale": { + "max": 1, + "min": 1, + }, + "parameter_overrides": {"foo": {"value": "value"}}, + } + }, + name="name", + regions=[1, 2], + api_keys=["key1", "key2"], + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.inference.applications.deployments.with_raw_response.create( + project_id=1, + application_name="demo-app", + components_configuration={ + "model": { + "exposed": True, + "flavor": "inference-16vcpu-232gib-1xh100-80gb", + "scale": { + "max": 1, + "min": 1, + }, + } + }, + name="name", + regions=[1, 2], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.inference.applications.deployments.with_streaming_response.create( + project_id=1, + application_name="demo-app", + components_configuration={ + "model": { + "exposed": True, + "flavor": "inference-16vcpu-232gib-1xh100-80gb", + "scale": { + "max": 1, + "min": 1, + }, + } + }, + name="name", + regions=[1, 2], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + deployment = client.cloud.inference.applications.deployments.update( + deployment_name="deployment_name", + project_id=1, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + deployment = client.cloud.inference.applications.deployments.update( + deployment_name="deployment_name", + project_id=1, + api_keys=["key1", "key2"], + components_configuration={ + "model": { + "exposed": True, + "flavor": "flavor", + "parameter_overrides": {"foo": {"value": "value"}}, + "scale": { + "max": 2, + "min": 0, + }, + } + }, + regions=[1, 2], + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.inference.applications.deployments.with_raw_response.update( + deployment_name="deployment_name", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.inference.applications.deployments.with_streaming_response.update( + deployment_name="deployment_name", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + client.cloud.inference.applications.deployments.with_raw_response.update( + deployment_name="", + project_id=1, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + deployment = client.cloud.inference.applications.deployments.list( + project_id=1, + ) + assert_matches_type(InferenceApplicationDeploymentList, deployment, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.inference.applications.deployments.with_raw_response.list( + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(InferenceApplicationDeploymentList, deployment, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.inference.applications.deployments.with_streaming_response.list( + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(InferenceApplicationDeploymentList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + deployment = client.cloud.inference.applications.deployments.delete( + deployment_name="deployment_name", + project_id=1, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.inference.applications.deployments.with_raw_response.delete( + deployment_name="deployment_name", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.inference.applications.deployments.with_streaming_response.delete( + deployment_name="deployment_name", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + client.cloud.inference.applications.deployments.with_raw_response.delete( + deployment_name="", + project_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + deployment = client.cloud.inference.applications.deployments.get( + deployment_name="deployment_name", + project_id=1, + ) + assert_matches_type(InferenceApplicationDeployment, deployment, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.inference.applications.deployments.with_raw_response.get( + deployment_name="deployment_name", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(InferenceApplicationDeployment, deployment, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.inference.applications.deployments.with_streaming_response.get( + deployment_name="deployment_name", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(InferenceApplicationDeployment, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + client.cloud.inference.applications.deployments.with_raw_response.get( + deployment_name="", + project_id=1, + ) + + +class TestAsyncDeployments: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.applications.deployments.create( + project_id=1, + application_name="demo-app", + components_configuration={ + "model": { + "exposed": True, + "flavor": "inference-16vcpu-232gib-1xh100-80gb", + "scale": { + "max": 1, + "min": 1, + }, + } + }, + name="name", + regions=[1, 2], + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.applications.deployments.create( + project_id=1, + application_name="demo-app", + components_configuration={ + "model": { + "exposed": True, + "flavor": "inference-16vcpu-232gib-1xh100-80gb", + "scale": { + "max": 1, + "min": 1, + }, + "parameter_overrides": {"foo": {"value": "value"}}, + } + }, + name="name", + regions=[1, 2], + api_keys=["key1", "key2"], + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.applications.deployments.with_raw_response.create( + project_id=1, + application_name="demo-app", + components_configuration={ + "model": { + "exposed": True, + "flavor": "inference-16vcpu-232gib-1xh100-80gb", + "scale": { + "max": 1, + "min": 1, + }, + } + }, + name="name", + regions=[1, 2], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.applications.deployments.with_streaming_response.create( + project_id=1, + application_name="demo-app", + components_configuration={ + "model": { + "exposed": True, + "flavor": "inference-16vcpu-232gib-1xh100-80gb", + "scale": { + "max": 1, + "min": 1, + }, + } + }, + name="name", + regions=[1, 2], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.applications.deployments.update( + deployment_name="deployment_name", + project_id=1, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.applications.deployments.update( + deployment_name="deployment_name", + project_id=1, + api_keys=["key1", "key2"], + components_configuration={ + "model": { + "exposed": True, + "flavor": "flavor", + "parameter_overrides": {"foo": {"value": "value"}}, + "scale": { + "max": 2, + "min": 0, + }, + } + }, + regions=[1, 2], + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.applications.deployments.with_raw_response.update( + deployment_name="deployment_name", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.applications.deployments.with_streaming_response.update( + deployment_name="deployment_name", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + await async_client.cloud.inference.applications.deployments.with_raw_response.update( + deployment_name="", + project_id=1, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.applications.deployments.list( + project_id=1, + ) + assert_matches_type(InferenceApplicationDeploymentList, deployment, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.applications.deployments.with_raw_response.list( + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(InferenceApplicationDeploymentList, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.applications.deployments.with_streaming_response.list( + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(InferenceApplicationDeploymentList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.applications.deployments.delete( + deployment_name="deployment_name", + project_id=1, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.applications.deployments.with_raw_response.delete( + deployment_name="deployment_name", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.applications.deployments.with_streaming_response.delete( + deployment_name="deployment_name", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + await async_client.cloud.inference.applications.deployments.with_raw_response.delete( + deployment_name="", + project_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.applications.deployments.get( + deployment_name="deployment_name", + project_id=1, + ) + assert_matches_type(InferenceApplicationDeployment, deployment, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.applications.deployments.with_raw_response.get( + deployment_name="deployment_name", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(InferenceApplicationDeployment, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.applications.deployments.with_streaming_response.get( + deployment_name="deployment_name", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(InferenceApplicationDeployment, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + await async_client.cloud.inference.applications.deployments.with_raw_response.get( + deployment_name="", + project_id=1, + ) diff --git a/tests/api_resources/cloud/inference/applications/test_templates.py b/tests/api_resources/cloud/inference/applications/test_templates.py new file mode 100644 index 00000000..aa0bfed8 --- /dev/null +++ b/tests/api_resources/cloud/inference/applications/test_templates.py @@ -0,0 +1,150 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.inference.applications import InferenceApplicationTemplate, InferenceApplicationTemplateList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTemplates: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + template = client.cloud.inference.applications.templates.list() + assert_matches_type(InferenceApplicationTemplateList, template, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.inference.applications.templates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = response.parse() + assert_matches_type(InferenceApplicationTemplateList, template, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.inference.applications.templates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = response.parse() + assert_matches_type(InferenceApplicationTemplateList, template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + template = client.cloud.inference.applications.templates.get( + "26f1kl-.n.71", + ) + assert_matches_type(InferenceApplicationTemplate, template, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.inference.applications.templates.with_raw_response.get( + "26f1kl-.n.71", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = response.parse() + assert_matches_type(InferenceApplicationTemplate, template, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.inference.applications.templates.with_streaming_response.get( + "26f1kl-.n.71", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = response.parse() + assert_matches_type(InferenceApplicationTemplate, template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `application_name` but received ''"): + client.cloud.inference.applications.templates.with_raw_response.get( + "", + ) + + +class TestAsyncTemplates: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + template = await async_client.cloud.inference.applications.templates.list() + assert_matches_type(InferenceApplicationTemplateList, template, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.applications.templates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = await response.parse() + assert_matches_type(InferenceApplicationTemplateList, template, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.applications.templates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = await response.parse() + assert_matches_type(InferenceApplicationTemplateList, template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + template = await async_client.cloud.inference.applications.templates.get( + "26f1kl-.n.71", + ) + assert_matches_type(InferenceApplicationTemplate, template, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.applications.templates.with_raw_response.get( + "26f1kl-.n.71", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = await response.parse() + assert_matches_type(InferenceApplicationTemplate, template, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.applications.templates.with_streaming_response.get( + "26f1kl-.n.71", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = await response.parse() + assert_matches_type(InferenceApplicationTemplate, template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `application_name` but received ''"): + await async_client.cloud.inference.applications.templates.with_raw_response.get( + "", + ) diff --git a/tests/api_resources/cloud/inference/deployments/__init__.py b/tests/api_resources/cloud/inference/deployments/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/inference/deployments/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/inference/deployments/test_logs.py b/tests/api_resources/cloud/inference/deployments/test_logs.py new file mode 100644 index 00000000..154af80c --- /dev/null +++ b/tests/api_resources/cloud/inference/deployments/test_logs.py @@ -0,0 +1,133 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud.inference.deployments import InferenceDeploymentLog + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestLogs: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + log = client.cloud.inference.deployments.logs.list( + deployment_name="my-instance", + project_id=1, + ) + assert_matches_type(SyncOffsetPage[InferenceDeploymentLog], log, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + log = client.cloud.inference.deployments.logs.list( + deployment_name="my-instance", + project_id=1, + limit=1000, + offset=0, + order_by="time.asc", + region_id=1, + ) + assert_matches_type(SyncOffsetPage[InferenceDeploymentLog], log, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.inference.deployments.logs.with_raw_response.list( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + log = response.parse() + assert_matches_type(SyncOffsetPage[InferenceDeploymentLog], log, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.inference.deployments.logs.with_streaming_response.list( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + log = response.parse() + assert_matches_type(SyncOffsetPage[InferenceDeploymentLog], log, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + client.cloud.inference.deployments.logs.with_raw_response.list( + deployment_name="", + project_id=1, + ) + + +class TestAsyncLogs: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + log = await async_client.cloud.inference.deployments.logs.list( + deployment_name="my-instance", + project_id=1, + ) + assert_matches_type(AsyncOffsetPage[InferenceDeploymentLog], log, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + log = await async_client.cloud.inference.deployments.logs.list( + deployment_name="my-instance", + project_id=1, + limit=1000, + offset=0, + order_by="time.asc", + region_id=1, + ) + assert_matches_type(AsyncOffsetPage[InferenceDeploymentLog], log, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.deployments.logs.with_raw_response.list( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + log = await response.parse() + assert_matches_type(AsyncOffsetPage[InferenceDeploymentLog], log, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.deployments.logs.with_streaming_response.list( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + log = await response.parse() + assert_matches_type(AsyncOffsetPage[InferenceDeploymentLog], log, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + await async_client.cloud.inference.deployments.logs.with_raw_response.list( + deployment_name="", + project_id=1, + ) diff --git a/tests/api_resources/cloud/inference/test_api_keys.py b/tests/api_resources/cloud/inference/test_api_keys.py new file mode 100644 index 00000000..5afddf66 --- /dev/null +++ b/tests/api_resources/cloud/inference/test_api_keys.py @@ -0,0 +1,466 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud.inference import ( + InferenceAPIKey, + InferenceAPIKeyCreated, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAPIKeys: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + api_key = client.cloud.inference.api_keys.create( + project_id=1, + name="my-api-key", + ) + assert_matches_type(InferenceAPIKeyCreated, api_key, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + api_key = client.cloud.inference.api_keys.create( + project_id=1, + name="my-api-key", + description="This key is used for accessing the inference service.", + expires_at="2024-10-01T12:00:00Z", + ) + assert_matches_type(InferenceAPIKeyCreated, api_key, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.inference.api_keys.with_raw_response.create( + project_id=1, + name="my-api-key", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = response.parse() + assert_matches_type(InferenceAPIKeyCreated, api_key, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.inference.api_keys.with_streaming_response.create( + project_id=1, + name="my-api-key", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = response.parse() + assert_matches_type(InferenceAPIKeyCreated, api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + api_key = client.cloud.inference.api_keys.update( + api_key_name="aws-dev", + project_id=1, + ) + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + api_key = client.cloud.inference.api_keys.update( + api_key_name="aws-dev", + project_id=1, + description="This key is used for accessing the inference service.", + ) + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.inference.api_keys.with_raw_response.update( + api_key_name="aws-dev", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = response.parse() + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.inference.api_keys.with_streaming_response.update( + api_key_name="aws-dev", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = response.parse() + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `api_key_name` but received ''"): + client.cloud.inference.api_keys.with_raw_response.update( + api_key_name="", + project_id=1, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + api_key = client.cloud.inference.api_keys.list( + project_id=1, + ) + assert_matches_type(SyncOffsetPage[InferenceAPIKey], api_key, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + api_key = client.cloud.inference.api_keys.list( + project_id=1, + limit=100, + offset=0, + ) + assert_matches_type(SyncOffsetPage[InferenceAPIKey], api_key, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.inference.api_keys.with_raw_response.list( + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = response.parse() + assert_matches_type(SyncOffsetPage[InferenceAPIKey], api_key, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.inference.api_keys.with_streaming_response.list( + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = response.parse() + assert_matches_type(SyncOffsetPage[InferenceAPIKey], api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + api_key = client.cloud.inference.api_keys.delete( + api_key_name="aws-dev", + project_id=1, + ) + assert api_key is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.inference.api_keys.with_raw_response.delete( + api_key_name="aws-dev", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = response.parse() + assert api_key is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.inference.api_keys.with_streaming_response.delete( + api_key_name="aws-dev", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = response.parse() + assert api_key is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `api_key_name` but received ''"): + client.cloud.inference.api_keys.with_raw_response.delete( + api_key_name="", + project_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + api_key = client.cloud.inference.api_keys.get( + api_key_name="aws-dev", + project_id=1, + ) + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.inference.api_keys.with_raw_response.get( + api_key_name="aws-dev", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = response.parse() + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.inference.api_keys.with_streaming_response.get( + api_key_name="aws-dev", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = response.parse() + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `api_key_name` but received ''"): + client.cloud.inference.api_keys.with_raw_response.get( + api_key_name="", + project_id=1, + ) + + +class TestAsyncAPIKeys: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + api_key = await async_client.cloud.inference.api_keys.create( + project_id=1, + name="my-api-key", + ) + assert_matches_type(InferenceAPIKeyCreated, api_key, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + api_key = await async_client.cloud.inference.api_keys.create( + project_id=1, + name="my-api-key", + description="This key is used for accessing the inference service.", + expires_at="2024-10-01T12:00:00Z", + ) + assert_matches_type(InferenceAPIKeyCreated, api_key, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.api_keys.with_raw_response.create( + project_id=1, + name="my-api-key", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = await response.parse() + assert_matches_type(InferenceAPIKeyCreated, api_key, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.api_keys.with_streaming_response.create( + project_id=1, + name="my-api-key", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = await response.parse() + assert_matches_type(InferenceAPIKeyCreated, api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + api_key = await async_client.cloud.inference.api_keys.update( + api_key_name="aws-dev", + project_id=1, + ) + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + api_key = await async_client.cloud.inference.api_keys.update( + api_key_name="aws-dev", + project_id=1, + description="This key is used for accessing the inference service.", + ) + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.api_keys.with_raw_response.update( + api_key_name="aws-dev", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = await response.parse() + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.api_keys.with_streaming_response.update( + api_key_name="aws-dev", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = await response.parse() + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `api_key_name` but received ''"): + await async_client.cloud.inference.api_keys.with_raw_response.update( + api_key_name="", + project_id=1, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + api_key = await async_client.cloud.inference.api_keys.list( + project_id=1, + ) + assert_matches_type(AsyncOffsetPage[InferenceAPIKey], api_key, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + api_key = await async_client.cloud.inference.api_keys.list( + project_id=1, + limit=100, + offset=0, + ) + assert_matches_type(AsyncOffsetPage[InferenceAPIKey], api_key, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.api_keys.with_raw_response.list( + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = await response.parse() + assert_matches_type(AsyncOffsetPage[InferenceAPIKey], api_key, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.api_keys.with_streaming_response.list( + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = await response.parse() + assert_matches_type(AsyncOffsetPage[InferenceAPIKey], api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + api_key = await async_client.cloud.inference.api_keys.delete( + api_key_name="aws-dev", + project_id=1, + ) + assert api_key is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.api_keys.with_raw_response.delete( + api_key_name="aws-dev", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = await response.parse() + assert api_key is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.api_keys.with_streaming_response.delete( + api_key_name="aws-dev", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = await response.parse() + assert api_key is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `api_key_name` but received ''"): + await async_client.cloud.inference.api_keys.with_raw_response.delete( + api_key_name="", + project_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + api_key = await async_client.cloud.inference.api_keys.get( + api_key_name="aws-dev", + project_id=1, + ) + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.api_keys.with_raw_response.get( + api_key_name="aws-dev", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_key = await response.parse() + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.api_keys.with_streaming_response.get( + api_key_name="aws-dev", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_key = await response.parse() + assert_matches_type(InferenceAPIKey, api_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `api_key_name` but received ''"): + await async_client.cloud.inference.api_keys.with_raw_response.get( + api_key_name="", + project_id=1, + ) diff --git a/tests/api_resources/cloud/inference/test_deployments.py b/tests/api_resources/cloud/inference/test_deployments.py new file mode 100644 index 00000000..a9e40264 --- /dev/null +++ b/tests/api_resources/cloud/inference/test_deployments.py @@ -0,0 +1,1237 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import TaskIDList +from gcore.types.cloud.inference import ( + InferenceDeployment, + InferenceDeploymentAPIKey, +) + +# pyright: reportDeprecated=false + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDeployments: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + deployment = client.cloud.inference.deployments.create( + project_id=1, + containers=[ + { + "region_id": 1, + "scale": { + "max": 3, + "min": 1, + }, + } + ], + flavor_name="inference-16vcpu-232gib-1xh100-80gb", + image="nginx:latest", + listening_port=80, + name="my-instance", + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + deployment = client.cloud.inference.deployments.create( + project_id=1, + containers=[ + { + "region_id": 1, + "scale": { + "max": 3, + "min": 1, + "cooldown_period": 60, + "polling_interval": 30, + "triggers": { + "cpu": {"threshold": 80}, + "gpu_memory": {"threshold": 80}, + "gpu_utilization": {"threshold": 80}, + "http": { + "rate": 1, + "window": 60, + }, + "memory": {"threshold": 70}, + "sqs": { + "activation_queue_length": 1, + "aws_region": "us-east-1", + "queue_length": 10, + "queue_url": "https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue", + "secret_name": "x", + "aws_endpoint": "aws_endpoint", + "scale_on_delayed": True, + "scale_on_flight": True, + }, + }, + }, + } + ], + flavor_name="inference-16vcpu-232gib-1xh100-80gb", + image="nginx:latest", + listening_port=80, + name="my-instance", + api_keys=["key1", "key2"], + auth_enabled=False, + command=["nginx", "-g", "daemon off;"], + credentials_name="dockerhub", + description="My first instance", + envs={ + "DEBUG_MODE": "False", + "KEY": "12345", + }, + ingress_opts={"disable_response_buffering": True}, + logging={ + "destination_region_id": 1, + "enabled": True, + "retention_policy": {"period": 42}, + "topic_name": "my-log-name", + }, + probes={ + "liveness_probe": { + "enabled": True, + "probe": { + "exec": {"command": ["ls", "-l"]}, + "failure_threshold": 3, + "http_get": { + "port": 80, + "headers": {"Authorization": "Bearer token 123"}, + "host": "127.0.0.1", + "path": "/healthz", + "schema": "HTTP", + }, + "initial_delay_seconds": 0, + "period_seconds": 5, + "success_threshold": 1, + "tcp_socket": {"port": 80}, + "timeout_seconds": 1, + }, + }, + "readiness_probe": { + "enabled": True, + "probe": { + "exec": {"command": ["ls", "-l"]}, + "failure_threshold": 3, + "http_get": { + "port": 80, + "headers": {"Authorization": "Bearer token 123"}, + "host": "127.0.0.1", + "path": "/healthz", + "schema": "HTTP", + }, + "initial_delay_seconds": 0, + "period_seconds": 5, + "success_threshold": 1, + "tcp_socket": {"port": 80}, + "timeout_seconds": 1, + }, + }, + "startup_probe": { + "enabled": True, + "probe": { + "exec": {"command": ["ls", "-l"]}, + "failure_threshold": 3, + "http_get": { + "port": 80, + "headers": {"Authorization": "Bearer token 123"}, + "host": "127.0.0.1", + "path": "/healthz", + "schema": "HTTP", + }, + "initial_delay_seconds": 0, + "period_seconds": 5, + "success_threshold": 1, + "tcp_socket": {"port": 80}, + "timeout_seconds": 1, + }, + }, + }, + api_timeout=120, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.inference.deployments.with_raw_response.create( + project_id=1, + containers=[ + { + "region_id": 1, + "scale": { + "max": 3, + "min": 1, + }, + } + ], + flavor_name="inference-16vcpu-232gib-1xh100-80gb", + image="nginx:latest", + listening_port=80, + name="my-instance", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.inference.deployments.with_streaming_response.create( + project_id=1, + containers=[ + { + "region_id": 1, + "scale": { + "max": 3, + "min": 1, + }, + } + ], + flavor_name="inference-16vcpu-232gib-1xh100-80gb", + image="nginx:latest", + listening_port=80, + name="my-instance", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + deployment = client.cloud.inference.deployments.update( + deployment_name="my-instance", + project_id=1, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + deployment = client.cloud.inference.deployments.update( + deployment_name="my-instance", + project_id=1, + api_keys=["key1", "key2"], + auth_enabled=False, + command=["nginx", "-g", "daemon off;"], + containers=[ + { + "region_id": 1337, + "scale": { + "max": 3, + "min": 1, + "cooldown_period": 60, + "polling_interval": 30, + "triggers": { + "cpu": {"threshold": 75}, + "gpu_memory": {"threshold": 80}, + "gpu_utilization": {"threshold": 80}, + "http": { + "rate": 1, + "window": 60, + }, + "memory": {"threshold": 80}, + "sqs": { + "activation_queue_length": 1, + "aws_region": "us-east-1", + "queue_length": 10, + "queue_url": "https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue", + "secret_name": "x", + "aws_endpoint": "aws_endpoint", + "scale_on_delayed": True, + "scale_on_flight": True, + }, + }, + }, + } + ], + credentials_name="dockerhub", + description="My first instance", + envs={ + "DEBUG_MODE": "False", + "KEY": "12345", + }, + flavor_name="inference-16vcpu-232gib-1xh100-80gb", + image="nginx:latest", + ingress_opts={"disable_response_buffering": True}, + listening_port=80, + logging={ + "destination_region_id": 1, + "enabled": True, + "retention_policy": {"period": 42}, + "topic_name": "my-log-name", + }, + probes={ + "liveness_probe": { + "enabled": True, + "probe": { + "exec": {"command": ["ls", "-l"]}, + "failure_threshold": 3, + "http_get": { + "headers": {"Authorization": "Bearer token 123"}, + "host": "127.0.0.1", + "path": "/healthz", + "port": 80, + "schema": "HTTP", + }, + "initial_delay_seconds": 0, + "period_seconds": 5, + "success_threshold": 1, + "tcp_socket": {"port": 80}, + "timeout_seconds": 1, + }, + }, + "readiness_probe": { + "enabled": True, + "probe": { + "exec": {"command": ["ls", "-l"]}, + "failure_threshold": 3, + "http_get": { + "headers": {"Authorization": "Bearer token 123"}, + "host": "127.0.0.1", + "path": "/healthz", + "port": 80, + "schema": "HTTP", + }, + "initial_delay_seconds": 0, + "period_seconds": 5, + "success_threshold": 1, + "tcp_socket": {"port": 80}, + "timeout_seconds": 1, + }, + }, + "startup_probe": { + "enabled": True, + "probe": { + "exec": {"command": ["ls", "-l"]}, + "failure_threshold": 3, + "http_get": { + "headers": {"Authorization": "Bearer token 123"}, + "host": "127.0.0.1", + "path": "/healthz", + "port": 80, + "schema": "HTTP", + }, + "initial_delay_seconds": 0, + "period_seconds": 5, + "success_threshold": 1, + "tcp_socket": {"port": 80}, + "timeout_seconds": 1, + }, + }, + }, + api_timeout=120, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.inference.deployments.with_raw_response.update( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.inference.deployments.with_streaming_response.update( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + client.cloud.inference.deployments.with_raw_response.update( + deployment_name="", + project_id=1, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + deployment = client.cloud.inference.deployments.list( + project_id=1, + ) + assert_matches_type(SyncOffsetPage[InferenceDeployment], deployment, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + deployment = client.cloud.inference.deployments.list( + project_id=1, + limit=1000, + offset=0, + ) + assert_matches_type(SyncOffsetPage[InferenceDeployment], deployment, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.inference.deployments.with_raw_response.list( + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(SyncOffsetPage[InferenceDeployment], deployment, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.inference.deployments.with_streaming_response.list( + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(SyncOffsetPage[InferenceDeployment], deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + deployment = client.cloud.inference.deployments.delete( + deployment_name="my-instance", + project_id=1, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.inference.deployments.with_raw_response.delete( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.inference.deployments.with_streaming_response.delete( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + client.cloud.inference.deployments.with_raw_response.delete( + deployment_name="", + project_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + deployment = client.cloud.inference.deployments.get( + deployment_name="my-instance", + project_id=1, + ) + assert_matches_type(InferenceDeployment, deployment, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.inference.deployments.with_raw_response.get( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(InferenceDeployment, deployment, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.inference.deployments.with_streaming_response.get( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(InferenceDeployment, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + client.cloud.inference.deployments.with_raw_response.get( + deployment_name="", + project_id=1, + ) + + @parametrize + def test_method_get_api_key(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + deployment = client.cloud.inference.deployments.get_api_key( + deployment_name="my-instance", + project_id=1, + ) + + assert_matches_type(InferenceDeploymentAPIKey, deployment, path=["response"]) + + @parametrize + def test_raw_response_get_api_key(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + response = client.cloud.inference.deployments.with_raw_response.get_api_key( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(InferenceDeploymentAPIKey, deployment, path=["response"]) + + @parametrize + def test_streaming_response_get_api_key(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with client.cloud.inference.deployments.with_streaming_response.get_api_key( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(InferenceDeploymentAPIKey, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_api_key(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + client.cloud.inference.deployments.with_raw_response.get_api_key( + deployment_name="", + project_id=1, + ) + + @parametrize + def test_method_start(self, client: Gcore) -> None: + deployment = client.cloud.inference.deployments.start( + deployment_name="my-instance", + project_id=1, + ) + assert deployment is None + + @parametrize + def test_raw_response_start(self, client: Gcore) -> None: + response = client.cloud.inference.deployments.with_raw_response.start( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert deployment is None + + @parametrize + def test_streaming_response_start(self, client: Gcore) -> None: + with client.cloud.inference.deployments.with_streaming_response.start( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert deployment is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_start(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + client.cloud.inference.deployments.with_raw_response.start( + deployment_name="", + project_id=1, + ) + + @parametrize + def test_method_stop(self, client: Gcore) -> None: + deployment = client.cloud.inference.deployments.stop( + deployment_name="my-instance", + project_id=1, + ) + assert deployment is None + + @parametrize + def test_raw_response_stop(self, client: Gcore) -> None: + response = client.cloud.inference.deployments.with_raw_response.stop( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert deployment is None + + @parametrize + def test_streaming_response_stop(self, client: Gcore) -> None: + with client.cloud.inference.deployments.with_streaming_response.stop( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert deployment is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_stop(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + client.cloud.inference.deployments.with_raw_response.stop( + deployment_name="", + project_id=1, + ) + + +class TestAsyncDeployments: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.deployments.create( + project_id=1, + containers=[ + { + "region_id": 1, + "scale": { + "max": 3, + "min": 1, + }, + } + ], + flavor_name="inference-16vcpu-232gib-1xh100-80gb", + image="nginx:latest", + listening_port=80, + name="my-instance", + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.deployments.create( + project_id=1, + containers=[ + { + "region_id": 1, + "scale": { + "max": 3, + "min": 1, + "cooldown_period": 60, + "polling_interval": 30, + "triggers": { + "cpu": {"threshold": 80}, + "gpu_memory": {"threshold": 80}, + "gpu_utilization": {"threshold": 80}, + "http": { + "rate": 1, + "window": 60, + }, + "memory": {"threshold": 70}, + "sqs": { + "activation_queue_length": 1, + "aws_region": "us-east-1", + "queue_length": 10, + "queue_url": "https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue", + "secret_name": "x", + "aws_endpoint": "aws_endpoint", + "scale_on_delayed": True, + "scale_on_flight": True, + }, + }, + }, + } + ], + flavor_name="inference-16vcpu-232gib-1xh100-80gb", + image="nginx:latest", + listening_port=80, + name="my-instance", + api_keys=["key1", "key2"], + auth_enabled=False, + command=["nginx", "-g", "daemon off;"], + credentials_name="dockerhub", + description="My first instance", + envs={ + "DEBUG_MODE": "False", + "KEY": "12345", + }, + ingress_opts={"disable_response_buffering": True}, + logging={ + "destination_region_id": 1, + "enabled": True, + "retention_policy": {"period": 42}, + "topic_name": "my-log-name", + }, + probes={ + "liveness_probe": { + "enabled": True, + "probe": { + "exec": {"command": ["ls", "-l"]}, + "failure_threshold": 3, + "http_get": { + "port": 80, + "headers": {"Authorization": "Bearer token 123"}, + "host": "127.0.0.1", + "path": "/healthz", + "schema": "HTTP", + }, + "initial_delay_seconds": 0, + "period_seconds": 5, + "success_threshold": 1, + "tcp_socket": {"port": 80}, + "timeout_seconds": 1, + }, + }, + "readiness_probe": { + "enabled": True, + "probe": { + "exec": {"command": ["ls", "-l"]}, + "failure_threshold": 3, + "http_get": { + "port": 80, + "headers": {"Authorization": "Bearer token 123"}, + "host": "127.0.0.1", + "path": "/healthz", + "schema": "HTTP", + }, + "initial_delay_seconds": 0, + "period_seconds": 5, + "success_threshold": 1, + "tcp_socket": {"port": 80}, + "timeout_seconds": 1, + }, + }, + "startup_probe": { + "enabled": True, + "probe": { + "exec": {"command": ["ls", "-l"]}, + "failure_threshold": 3, + "http_get": { + "port": 80, + "headers": {"Authorization": "Bearer token 123"}, + "host": "127.0.0.1", + "path": "/healthz", + "schema": "HTTP", + }, + "initial_delay_seconds": 0, + "period_seconds": 5, + "success_threshold": 1, + "tcp_socket": {"port": 80}, + "timeout_seconds": 1, + }, + }, + }, + api_timeout=120, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.deployments.with_raw_response.create( + project_id=1, + containers=[ + { + "region_id": 1, + "scale": { + "max": 3, + "min": 1, + }, + } + ], + flavor_name="inference-16vcpu-232gib-1xh100-80gb", + image="nginx:latest", + listening_port=80, + name="my-instance", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.deployments.with_streaming_response.create( + project_id=1, + containers=[ + { + "region_id": 1, + "scale": { + "max": 3, + "min": 1, + }, + } + ], + flavor_name="inference-16vcpu-232gib-1xh100-80gb", + image="nginx:latest", + listening_port=80, + name="my-instance", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.deployments.update( + deployment_name="my-instance", + project_id=1, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.deployments.update( + deployment_name="my-instance", + project_id=1, + api_keys=["key1", "key2"], + auth_enabled=False, + command=["nginx", "-g", "daemon off;"], + containers=[ + { + "region_id": 1337, + "scale": { + "max": 3, + "min": 1, + "cooldown_period": 60, + "polling_interval": 30, + "triggers": { + "cpu": {"threshold": 75}, + "gpu_memory": {"threshold": 80}, + "gpu_utilization": {"threshold": 80}, + "http": { + "rate": 1, + "window": 60, + }, + "memory": {"threshold": 80}, + "sqs": { + "activation_queue_length": 1, + "aws_region": "us-east-1", + "queue_length": 10, + "queue_url": "https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue", + "secret_name": "x", + "aws_endpoint": "aws_endpoint", + "scale_on_delayed": True, + "scale_on_flight": True, + }, + }, + }, + } + ], + credentials_name="dockerhub", + description="My first instance", + envs={ + "DEBUG_MODE": "False", + "KEY": "12345", + }, + flavor_name="inference-16vcpu-232gib-1xh100-80gb", + image="nginx:latest", + ingress_opts={"disable_response_buffering": True}, + listening_port=80, + logging={ + "destination_region_id": 1, + "enabled": True, + "retention_policy": {"period": 42}, + "topic_name": "my-log-name", + }, + probes={ + "liveness_probe": { + "enabled": True, + "probe": { + "exec": {"command": ["ls", "-l"]}, + "failure_threshold": 3, + "http_get": { + "headers": {"Authorization": "Bearer token 123"}, + "host": "127.0.0.1", + "path": "/healthz", + "port": 80, + "schema": "HTTP", + }, + "initial_delay_seconds": 0, + "period_seconds": 5, + "success_threshold": 1, + "tcp_socket": {"port": 80}, + "timeout_seconds": 1, + }, + }, + "readiness_probe": { + "enabled": True, + "probe": { + "exec": {"command": ["ls", "-l"]}, + "failure_threshold": 3, + "http_get": { + "headers": {"Authorization": "Bearer token 123"}, + "host": "127.0.0.1", + "path": "/healthz", + "port": 80, + "schema": "HTTP", + }, + "initial_delay_seconds": 0, + "period_seconds": 5, + "success_threshold": 1, + "tcp_socket": {"port": 80}, + "timeout_seconds": 1, + }, + }, + "startup_probe": { + "enabled": True, + "probe": { + "exec": {"command": ["ls", "-l"]}, + "failure_threshold": 3, + "http_get": { + "headers": {"Authorization": "Bearer token 123"}, + "host": "127.0.0.1", + "path": "/healthz", + "port": 80, + "schema": "HTTP", + }, + "initial_delay_seconds": 0, + "period_seconds": 5, + "success_threshold": 1, + "tcp_socket": {"port": 80}, + "timeout_seconds": 1, + }, + }, + }, + api_timeout=120, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.deployments.with_raw_response.update( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.deployments.with_streaming_response.update( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + await async_client.cloud.inference.deployments.with_raw_response.update( + deployment_name="", + project_id=1, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.deployments.list( + project_id=1, + ) + assert_matches_type(AsyncOffsetPage[InferenceDeployment], deployment, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.deployments.list( + project_id=1, + limit=1000, + offset=0, + ) + assert_matches_type(AsyncOffsetPage[InferenceDeployment], deployment, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.deployments.with_raw_response.list( + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(AsyncOffsetPage[InferenceDeployment], deployment, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.deployments.with_streaming_response.list( + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(AsyncOffsetPage[InferenceDeployment], deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.deployments.delete( + deployment_name="my-instance", + project_id=1, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.deployments.with_raw_response.delete( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.deployments.with_streaming_response.delete( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(TaskIDList, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + await async_client.cloud.inference.deployments.with_raw_response.delete( + deployment_name="", + project_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.deployments.get( + deployment_name="my-instance", + project_id=1, + ) + assert_matches_type(InferenceDeployment, deployment, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.deployments.with_raw_response.get( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(InferenceDeployment, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.deployments.with_streaming_response.get( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(InferenceDeployment, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + await async_client.cloud.inference.deployments.with_raw_response.get( + deployment_name="", + project_id=1, + ) + + @parametrize + async def test_method_get_api_key(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + deployment = await async_client.cloud.inference.deployments.get_api_key( + deployment_name="my-instance", + project_id=1, + ) + + assert_matches_type(InferenceDeploymentAPIKey, deployment, path=["response"]) + + @parametrize + async def test_raw_response_get_api_key(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + response = await async_client.cloud.inference.deployments.with_raw_response.get_api_key( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(InferenceDeploymentAPIKey, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_get_api_key(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + async with async_client.cloud.inference.deployments.with_streaming_response.get_api_key( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(InferenceDeploymentAPIKey, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_api_key(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + await async_client.cloud.inference.deployments.with_raw_response.get_api_key( + deployment_name="", + project_id=1, + ) + + @parametrize + async def test_method_start(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.deployments.start( + deployment_name="my-instance", + project_id=1, + ) + assert deployment is None + + @parametrize + async def test_raw_response_start(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.deployments.with_raw_response.start( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert deployment is None + + @parametrize + async def test_streaming_response_start(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.deployments.with_streaming_response.start( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert deployment is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_start(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + await async_client.cloud.inference.deployments.with_raw_response.start( + deployment_name="", + project_id=1, + ) + + @parametrize + async def test_method_stop(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.deployments.stop( + deployment_name="my-instance", + project_id=1, + ) + assert deployment is None + + @parametrize + async def test_raw_response_stop(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.deployments.with_raw_response.stop( + deployment_name="my-instance", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert deployment is None + + @parametrize + async def test_streaming_response_stop(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.deployments.with_streaming_response.stop( + deployment_name="my-instance", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert deployment is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_stop(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_name` but received ''"): + await async_client.cloud.inference.deployments.with_raw_response.stop( + deployment_name="", + project_id=1, + ) diff --git a/tests/api_resources/cloud/inference/test_flavors.py b/tests/api_resources/cloud/inference/test_flavors.py new file mode 100644 index 00000000..2de7d73e --- /dev/null +++ b/tests/api_resources/cloud/inference/test_flavors.py @@ -0,0 +1,167 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud.inference import InferenceFlavor + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFlavors: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + flavor = client.cloud.inference.flavors.list() + assert_matches_type(SyncOffsetPage[InferenceFlavor], flavor, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + flavor = client.cloud.inference.flavors.list( + limit=1000, + offset=0, + ) + assert_matches_type(SyncOffsetPage[InferenceFlavor], flavor, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.inference.flavors.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = response.parse() + assert_matches_type(SyncOffsetPage[InferenceFlavor], flavor, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.inference.flavors.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = response.parse() + assert_matches_type(SyncOffsetPage[InferenceFlavor], flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + flavor = client.cloud.inference.flavors.get( + "inference-16vcpu-232gib-1xh100-80gb", + ) + assert_matches_type(InferenceFlavor, flavor, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.inference.flavors.with_raw_response.get( + "inference-16vcpu-232gib-1xh100-80gb", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = response.parse() + assert_matches_type(InferenceFlavor, flavor, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.inference.flavors.with_streaming_response.get( + "inference-16vcpu-232gib-1xh100-80gb", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = response.parse() + assert_matches_type(InferenceFlavor, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `flavor_name` but received ''"): + client.cloud.inference.flavors.with_raw_response.get( + "", + ) + + +class TestAsyncFlavors: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.inference.flavors.list() + assert_matches_type(AsyncOffsetPage[InferenceFlavor], flavor, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.inference.flavors.list( + limit=1000, + offset=0, + ) + assert_matches_type(AsyncOffsetPage[InferenceFlavor], flavor, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.flavors.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = await response.parse() + assert_matches_type(AsyncOffsetPage[InferenceFlavor], flavor, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.flavors.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = await response.parse() + assert_matches_type(AsyncOffsetPage[InferenceFlavor], flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.inference.flavors.get( + "inference-16vcpu-232gib-1xh100-80gb", + ) + assert_matches_type(InferenceFlavor, flavor, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.flavors.with_raw_response.get( + "inference-16vcpu-232gib-1xh100-80gb", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = await response.parse() + assert_matches_type(InferenceFlavor, flavor, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.flavors.with_streaming_response.get( + "inference-16vcpu-232gib-1xh100-80gb", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = await response.parse() + assert_matches_type(InferenceFlavor, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `flavor_name` but received ''"): + await async_client.cloud.inference.flavors.with_raw_response.get( + "", + ) diff --git a/tests/api_resources/cloud/inference/test_registry_credentials.py b/tests/api_resources/cloud/inference/test_registry_credentials.py new file mode 100644 index 00000000..2726feb8 --- /dev/null +++ b/tests/api_resources/cloud/inference/test_registry_credentials.py @@ -0,0 +1,469 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud.inference import ( + InferenceRegistryCredentials, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRegistryCredentials: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + registry_credential = client.cloud.inference.registry_credentials.create( + project_id=1, + name="docker-io", + password="password", + registry_url="registry.example.com", + username="username", + ) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.inference.registry_credentials.with_raw_response.create( + project_id=1, + name="docker-io", + password="password", + registry_url="registry.example.com", + username="username", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry_credential = response.parse() + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.inference.registry_credentials.with_streaming_response.create( + project_id=1, + name="docker-io", + password="password", + registry_url="registry.example.com", + username="username", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry_credential = response.parse() + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + registry_credential = client.cloud.inference.registry_credentials.list( + project_id=1, + ) + assert_matches_type(SyncOffsetPage[InferenceRegistryCredentials], registry_credential, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + registry_credential = client.cloud.inference.registry_credentials.list( + project_id=1, + limit=1000, + offset=0, + ) + assert_matches_type(SyncOffsetPage[InferenceRegistryCredentials], registry_credential, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.inference.registry_credentials.with_raw_response.list( + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry_credential = response.parse() + assert_matches_type(SyncOffsetPage[InferenceRegistryCredentials], registry_credential, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.inference.registry_credentials.with_streaming_response.list( + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry_credential = response.parse() + assert_matches_type(SyncOffsetPage[InferenceRegistryCredentials], registry_credential, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + registry_credential = client.cloud.inference.registry_credentials.delete( + credential_name="docker-io", + project_id=1, + ) + assert registry_credential is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.inference.registry_credentials.with_raw_response.delete( + credential_name="docker-io", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry_credential = response.parse() + assert registry_credential is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.inference.registry_credentials.with_streaming_response.delete( + credential_name="docker-io", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry_credential = response.parse() + assert registry_credential is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `credential_name` but received ''"): + client.cloud.inference.registry_credentials.with_raw_response.delete( + credential_name="", + project_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + registry_credential = client.cloud.inference.registry_credentials.get( + credential_name="docker-io", + project_id=1, + ) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.inference.registry_credentials.with_raw_response.get( + credential_name="docker-io", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry_credential = response.parse() + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.inference.registry_credentials.with_streaming_response.get( + credential_name="docker-io", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry_credential = response.parse() + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `credential_name` but received ''"): + client.cloud.inference.registry_credentials.with_raw_response.get( + credential_name="", + project_id=1, + ) + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + registry_credential = client.cloud.inference.registry_credentials.replace( + credential_name="docker-io", + project_id=1, + password="password", + registry_url="registry.example.com", + username="username", + ) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.cloud.inference.registry_credentials.with_raw_response.replace( + credential_name="docker-io", + project_id=1, + password="password", + registry_url="registry.example.com", + username="username", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry_credential = response.parse() + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.cloud.inference.registry_credentials.with_streaming_response.replace( + credential_name="docker-io", + project_id=1, + password="password", + registry_url="registry.example.com", + username="username", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry_credential = response.parse() + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_replace(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `credential_name` but received ''"): + client.cloud.inference.registry_credentials.with_raw_response.replace( + credential_name="", + project_id=1, + password="password", + registry_url="registry.example.com", + username="username", + ) + + +class TestAsyncRegistryCredentials: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + registry_credential = await async_client.cloud.inference.registry_credentials.create( + project_id=1, + name="docker-io", + password="password", + registry_url="registry.example.com", + username="username", + ) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.registry_credentials.with_raw_response.create( + project_id=1, + name="docker-io", + password="password", + registry_url="registry.example.com", + username="username", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry_credential = await response.parse() + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.registry_credentials.with_streaming_response.create( + project_id=1, + name="docker-io", + password="password", + registry_url="registry.example.com", + username="username", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry_credential = await response.parse() + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + registry_credential = await async_client.cloud.inference.registry_credentials.list( + project_id=1, + ) + assert_matches_type(AsyncOffsetPage[InferenceRegistryCredentials], registry_credential, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + registry_credential = await async_client.cloud.inference.registry_credentials.list( + project_id=1, + limit=1000, + offset=0, + ) + assert_matches_type(AsyncOffsetPage[InferenceRegistryCredentials], registry_credential, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.registry_credentials.with_raw_response.list( + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry_credential = await response.parse() + assert_matches_type(AsyncOffsetPage[InferenceRegistryCredentials], registry_credential, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.registry_credentials.with_streaming_response.list( + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry_credential = await response.parse() + assert_matches_type(AsyncOffsetPage[InferenceRegistryCredentials], registry_credential, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + registry_credential = await async_client.cloud.inference.registry_credentials.delete( + credential_name="docker-io", + project_id=1, + ) + assert registry_credential is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.registry_credentials.with_raw_response.delete( + credential_name="docker-io", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry_credential = await response.parse() + assert registry_credential is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.registry_credentials.with_streaming_response.delete( + credential_name="docker-io", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry_credential = await response.parse() + assert registry_credential is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `credential_name` but received ''"): + await async_client.cloud.inference.registry_credentials.with_raw_response.delete( + credential_name="", + project_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + registry_credential = await async_client.cloud.inference.registry_credentials.get( + credential_name="docker-io", + project_id=1, + ) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.registry_credentials.with_raw_response.get( + credential_name="docker-io", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry_credential = await response.parse() + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.registry_credentials.with_streaming_response.get( + credential_name="docker-io", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry_credential = await response.parse() + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `credential_name` but received ''"): + await async_client.cloud.inference.registry_credentials.with_raw_response.get( + credential_name="", + project_id=1, + ) + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + registry_credential = await async_client.cloud.inference.registry_credentials.replace( + credential_name="docker-io", + project_id=1, + password="password", + registry_url="registry.example.com", + username="username", + ) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.registry_credentials.with_raw_response.replace( + credential_name="docker-io", + project_id=1, + password="password", + registry_url="registry.example.com", + username="username", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry_credential = await response.parse() + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.registry_credentials.with_streaming_response.replace( + credential_name="docker-io", + project_id=1, + password="password", + registry_url="registry.example.com", + username="username", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry_credential = await response.parse() + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_replace(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `credential_name` but received ''"): + await async_client.cloud.inference.registry_credentials.with_raw_response.replace( + credential_name="", + project_id=1, + password="password", + registry_url="registry.example.com", + username="username", + ) diff --git a/tests/api_resources/cloud/inference/test_secrets.py b/tests/api_resources/cloud/inference/test_secrets.py new file mode 100644 index 00000000..62ad7207 --- /dev/null +++ b/tests/api_resources/cloud/inference/test_secrets.py @@ -0,0 +1,495 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud.inference import InferenceSecret + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSecrets: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + secret = client.cloud.inference.secrets.create( + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + name="aws-dev", + type="aws-iam", + ) + assert_matches_type(InferenceSecret, secret, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.inference.secrets.with_raw_response.create( + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + name="aws-dev", + type="aws-iam", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(InferenceSecret, secret, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.inference.secrets.with_streaming_response.create( + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + name="aws-dev", + type="aws-iam", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(InferenceSecret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + secret = client.cloud.inference.secrets.list( + project_id=1, + ) + assert_matches_type(SyncOffsetPage[InferenceSecret], secret, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + secret = client.cloud.inference.secrets.list( + project_id=1, + limit=1000, + offset=0, + ) + assert_matches_type(SyncOffsetPage[InferenceSecret], secret, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.inference.secrets.with_raw_response.list( + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(SyncOffsetPage[InferenceSecret], secret, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.inference.secrets.with_streaming_response.list( + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(SyncOffsetPage[InferenceSecret], secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + secret = client.cloud.inference.secrets.delete( + secret_name="aws-dev", + project_id=1, + ) + assert secret is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.inference.secrets.with_raw_response.delete( + secret_name="aws-dev", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert secret is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.inference.secrets.with_streaming_response.delete( + secret_name="aws-dev", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert secret is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `secret_name` but received ''"): + client.cloud.inference.secrets.with_raw_response.delete( + secret_name="", + project_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + secret = client.cloud.inference.secrets.get( + secret_name="aws-dev", + project_id=1, + ) + assert_matches_type(InferenceSecret, secret, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.inference.secrets.with_raw_response.get( + secret_name="aws-dev", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(InferenceSecret, secret, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.inference.secrets.with_streaming_response.get( + secret_name="aws-dev", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(InferenceSecret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `secret_name` but received ''"): + client.cloud.inference.secrets.with_raw_response.get( + secret_name="", + project_id=1, + ) + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + secret = client.cloud.inference.secrets.replace( + secret_name="aws-dev", + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + type="aws-iam", + ) + assert_matches_type(InferenceSecret, secret, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.cloud.inference.secrets.with_raw_response.replace( + secret_name="aws-dev", + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + type="aws-iam", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(InferenceSecret, secret, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.cloud.inference.secrets.with_streaming_response.replace( + secret_name="aws-dev", + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + type="aws-iam", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(InferenceSecret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_replace(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `secret_name` but received ''"): + client.cloud.inference.secrets.with_raw_response.replace( + secret_name="", + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + type="aws-iam", + ) + + +class TestAsyncSecrets: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + secret = await async_client.cloud.inference.secrets.create( + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + name="aws-dev", + type="aws-iam", + ) + assert_matches_type(InferenceSecret, secret, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.secrets.with_raw_response.create( + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + name="aws-dev", + type="aws-iam", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(InferenceSecret, secret, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.secrets.with_streaming_response.create( + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + name="aws-dev", + type="aws-iam", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(InferenceSecret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + secret = await async_client.cloud.inference.secrets.list( + project_id=1, + ) + assert_matches_type(AsyncOffsetPage[InferenceSecret], secret, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + secret = await async_client.cloud.inference.secrets.list( + project_id=1, + limit=1000, + offset=0, + ) + assert_matches_type(AsyncOffsetPage[InferenceSecret], secret, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.secrets.with_raw_response.list( + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(AsyncOffsetPage[InferenceSecret], secret, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.secrets.with_streaming_response.list( + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(AsyncOffsetPage[InferenceSecret], secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + secret = await async_client.cloud.inference.secrets.delete( + secret_name="aws-dev", + project_id=1, + ) + assert secret is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.secrets.with_raw_response.delete( + secret_name="aws-dev", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert secret is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.secrets.with_streaming_response.delete( + secret_name="aws-dev", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert secret is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `secret_name` but received ''"): + await async_client.cloud.inference.secrets.with_raw_response.delete( + secret_name="", + project_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + secret = await async_client.cloud.inference.secrets.get( + secret_name="aws-dev", + project_id=1, + ) + assert_matches_type(InferenceSecret, secret, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.secrets.with_raw_response.get( + secret_name="aws-dev", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(InferenceSecret, secret, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.secrets.with_streaming_response.get( + secret_name="aws-dev", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(InferenceSecret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `secret_name` but received ''"): + await async_client.cloud.inference.secrets.with_raw_response.get( + secret_name="", + project_id=1, + ) + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + secret = await async_client.cloud.inference.secrets.replace( + secret_name="aws-dev", + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + type="aws-iam", + ) + assert_matches_type(InferenceSecret, secret, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.secrets.with_raw_response.replace( + secret_name="aws-dev", + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + type="aws-iam", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(InferenceSecret, secret, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.secrets.with_streaming_response.replace( + secret_name="aws-dev", + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + type="aws-iam", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(InferenceSecret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_replace(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `secret_name` but received ''"): + await async_client.cloud.inference.secrets.with_raw_response.replace( + secret_name="", + project_id=1, + data={ + "aws_access_key_id": "fake-key-id", + "aws_secret_access_key": "fake-secret", + }, + type="aws-iam", + ) diff --git a/tests/api_resources/cloud/instances/__init__.py b/tests/api_resources/cloud/instances/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/instances/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/instances/test_flavors.py b/tests/api_resources/cloud/instances/test_flavors.py new file mode 100644 index 00000000..51ff8119 --- /dev/null +++ b/tests/api_resources/cloud/instances/test_flavors.py @@ -0,0 +1,116 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.instances import InstanceFlavorList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFlavors: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + flavor = client.cloud.instances.flavors.list( + project_id=0, + region_id=0, + ) + assert_matches_type(InstanceFlavorList, flavor, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + flavor = client.cloud.instances.flavors.list( + project_id=0, + region_id=0, + disabled=True, + exclude_linux=True, + exclude_windows=True, + include_prices=True, + ) + assert_matches_type(InstanceFlavorList, flavor, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.instances.flavors.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = response.parse() + assert_matches_type(InstanceFlavorList, flavor, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.instances.flavors.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = response.parse() + assert_matches_type(InstanceFlavorList, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncFlavors: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.instances.flavors.list( + project_id=0, + region_id=0, + ) + assert_matches_type(InstanceFlavorList, flavor, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.instances.flavors.list( + project_id=0, + region_id=0, + disabled=True, + exclude_linux=True, + exclude_windows=True, + include_prices=True, + ) + assert_matches_type(InstanceFlavorList, flavor, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.flavors.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = await response.parse() + assert_matches_type(InstanceFlavorList, flavor, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.flavors.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = await response.parse() + assert_matches_type(InstanceFlavorList, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/instances/test_images.py b/tests/api_resources/cloud/instances/test_images.py new file mode 100644 index 00000000..b97decb0 --- /dev/null +++ b/tests/api_resources/cloud/instances/test_images.py @@ -0,0 +1,682 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import Image, ImageList, TaskIDList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestImages: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_update(self, client: Gcore) -> None: + image = client.cloud.instances.images.update( + image_id="image_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Image, image, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + image = client.cloud.instances.images.update( + image_id="image_id", + project_id=0, + region_id=0, + hw_firmware_type="bios", + hw_machine_type="q35", + is_baremetal=False, + name="my-image", + os_type="linux", + ssh_key="allow", + tags={}, + ) + assert_matches_type(Image, image, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.instances.images.with_raw_response.update( + image_id="image_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(Image, image, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.instances.images.with_streaming_response.update( + image_id="image_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(Image, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + client.cloud.instances.images.with_raw_response.update( + image_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + image = client.cloud.instances.images.list( + project_id=0, + region_id=0, + ) + assert_matches_type(ImageList, image, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + image = client.cloud.instances.images.list( + project_id=0, + region_id=0, + include_prices=True, + private="private", + tag_key=["string"], + tag_key_value="tag_key_value", + visibility="private", + ) + assert_matches_type(ImageList, image, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.instances.images.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(ImageList, image, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.instances.images.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(ImageList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + image = client.cloud.instances.images.delete( + image_id="image_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.instances.images.with_raw_response.delete( + image_id="image_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.instances.images.with_streaming_response.delete( + image_id="image_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + client.cloud.instances.images.with_raw_response.delete( + image_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_create_from_volume(self, client: Gcore) -> None: + image = client.cloud.instances.images.create_from_volume( + project_id=0, + region_id=0, + name="my-image", + volume_id="d478ae29-dedc-4869-82f0-96104425f565", + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_method_create_from_volume_with_all_params(self, client: Gcore) -> None: + image = client.cloud.instances.images.create_from_volume( + project_id=0, + region_id=0, + name="my-image", + volume_id="d478ae29-dedc-4869-82f0-96104425f565", + architecture="x86_64", + hw_firmware_type="bios", + hw_machine_type="q35", + is_baremetal=False, + os_type="linux", + source="volume", + ssh_key="allow", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_raw_response_create_from_volume(self, client: Gcore) -> None: + response = client.cloud.instances.images.with_raw_response.create_from_volume( + project_id=0, + region_id=0, + name="my-image", + volume_id="d478ae29-dedc-4869-82f0-96104425f565", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_streaming_response_create_from_volume(self, client: Gcore) -> None: + with client.cloud.instances.images.with_streaming_response.create_from_volume( + project_id=0, + region_id=0, + name="my-image", + volume_id="d478ae29-dedc-4869-82f0-96104425f565", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + image = client.cloud.instances.images.get( + image_id="image_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Image, image, path=["response"]) + + @parametrize + def test_method_get_with_all_params(self, client: Gcore) -> None: + image = client.cloud.instances.images.get( + image_id="image_id", + project_id=0, + region_id=0, + include_prices=True, + ) + assert_matches_type(Image, image, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.instances.images.with_raw_response.get( + image_id="image_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(Image, image, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.instances.images.with_streaming_response.get( + image_id="image_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(Image, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + client.cloud.instances.images.with_raw_response.get( + image_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_upload(self, client: Gcore) -> None: + image = client.cloud.instances.images.upload( + project_id=0, + region_id=0, + name="my-image", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_method_upload_with_all_params(self, client: Gcore) -> None: + image = client.cloud.instances.images.upload( + project_id=0, + region_id=0, + name="my-image", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + architecture="x86_64", + cow_format=False, + hw_firmware_type="bios", + hw_machine_type="q35", + is_baremetal=False, + os_distro="ubuntu", + os_type="linux", + os_version="22.04", + ssh_key="allow", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_raw_response_upload(self, client: Gcore) -> None: + response = client.cloud.instances.images.with_raw_response.upload( + project_id=0, + region_id=0, + name="my-image", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + def test_streaming_response_upload(self, client: Gcore) -> None: + with client.cloud.instances.images.with_streaming_response.upload( + project_id=0, + region_id=0, + name="my-image", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncImages: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.instances.images.update( + image_id="image_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Image, image, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.instances.images.update( + image_id="image_id", + project_id=0, + region_id=0, + hw_firmware_type="bios", + hw_machine_type="q35", + is_baremetal=False, + name="my-image", + os_type="linux", + ssh_key="allow", + tags={}, + ) + assert_matches_type(Image, image, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.images.with_raw_response.update( + image_id="image_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(Image, image, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.images.with_streaming_response.update( + image_id="image_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(Image, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + await async_client.cloud.instances.images.with_raw_response.update( + image_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.instances.images.list( + project_id=0, + region_id=0, + ) + assert_matches_type(ImageList, image, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.instances.images.list( + project_id=0, + region_id=0, + include_prices=True, + private="private", + tag_key=["string"], + tag_key_value="tag_key_value", + visibility="private", + ) + assert_matches_type(ImageList, image, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.images.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(ImageList, image, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.images.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(ImageList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.instances.images.delete( + image_id="image_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.images.with_raw_response.delete( + image_id="image_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.images.with_streaming_response.delete( + image_id="image_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + await async_client.cloud.instances.images.with_raw_response.delete( + image_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_create_from_volume(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.instances.images.create_from_volume( + project_id=0, + region_id=0, + name="my-image", + volume_id="d478ae29-dedc-4869-82f0-96104425f565", + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_method_create_from_volume_with_all_params(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.instances.images.create_from_volume( + project_id=0, + region_id=0, + name="my-image", + volume_id="d478ae29-dedc-4869-82f0-96104425f565", + architecture="x86_64", + hw_firmware_type="bios", + hw_machine_type="q35", + is_baremetal=False, + os_type="linux", + source="volume", + ssh_key="allow", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_raw_response_create_from_volume(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.images.with_raw_response.create_from_volume( + project_id=0, + region_id=0, + name="my-image", + volume_id="d478ae29-dedc-4869-82f0-96104425f565", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_streaming_response_create_from_volume(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.images.with_streaming_response.create_from_volume( + project_id=0, + region_id=0, + name="my-image", + volume_id="d478ae29-dedc-4869-82f0-96104425f565", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.instances.images.get( + image_id="image_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Image, image, path=["response"]) + + @parametrize + async def test_method_get_with_all_params(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.instances.images.get( + image_id="image_id", + project_id=0, + region_id=0, + include_prices=True, + ) + assert_matches_type(Image, image, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.images.with_raw_response.get( + image_id="image_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(Image, image, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.images.with_streaming_response.get( + image_id="image_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(Image, image, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `image_id` but received ''"): + await async_client.cloud.instances.images.with_raw_response.get( + image_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_upload(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.instances.images.upload( + project_id=0, + region_id=0, + name="my-image", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_method_upload_with_all_params(self, async_client: AsyncGcore) -> None: + image = await async_client.cloud.instances.images.upload( + project_id=0, + region_id=0, + name="my-image", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + architecture="x86_64", + cow_format=False, + hw_firmware_type="bios", + hw_machine_type="q35", + is_baremetal=False, + os_distro="ubuntu", + os_type="linux", + os_version="22.04", + ssh_key="allow", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_raw_response_upload(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.images.with_raw_response.upload( + project_id=0, + region_id=0, + name="my-image", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + @parametrize + async def test_streaming_response_upload(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.images.with_streaming_response.upload( + project_id=0, + region_id=0, + name="my-image", + url="http://mirror.noris.net/cirros/0.4.0/cirros-0.4.0-x86_64-disk.img", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + image = await response.parse() + assert_matches_type(TaskIDList, image, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/instances/test_interfaces.py b/tests/api_resources/cloud/instances/test_interfaces.py new file mode 100644 index 00000000..348e946d --- /dev/null +++ b/tests/api_resources/cloud/instances/test_interfaces.py @@ -0,0 +1,850 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import TaskIDList, NetworkInterfaceList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestInterfaces: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + interface = client.cloud.instances.interfaces.list( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(NetworkInterfaceList, interface, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.instances.interfaces.with_raw_response.list( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = response.parse() + assert_matches_type(NetworkInterfaceList, interface, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.instances.interfaces.with_streaming_response.list( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = response.parse() + assert_matches_type(NetworkInterfaceList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.interfaces.with_raw_response.list( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_attach_overload_1(self, client: Gcore) -> None: + interface = client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_method_attach_with_all_params_overload_1(self, client: Gcore) -> None: + interface = client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="interface_name", + ip_family="dual", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="external", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_raw_response_attach_overload_1(self, client: Gcore) -> None: + response = client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_streaming_response_attach_overload_1(self, client: Gcore) -> None: + with client.cloud.instances.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_attach_overload_1(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_attach_overload_2(self, client: Gcore) -> None: + interface = client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_method_attach_with_all_params_overload_2(self, client: Gcore) -> None: + interface = client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="my-subnet-interface", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="subnet", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_raw_response_attach_overload_2(self, client: Gcore) -> None: + response = client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_streaming_response_attach_overload_2(self, client: Gcore) -> None: + with client.cloud.instances.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_attach_overload_2(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + @parametrize + def test_method_attach_overload_3(self, client: Gcore) -> None: + interface = client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_method_attach_with_all_params_overload_3(self, client: Gcore) -> None: + interface = client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="my-any-subnet-interface", + ip_family="dual", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="any_subnet", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_raw_response_attach_overload_3(self, client: Gcore) -> None: + response = client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_streaming_response_attach_overload_3(self, client: Gcore) -> None: + with client.cloud.instances.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_attach_overload_3(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + @parametrize + def test_method_attach_overload_4(self, client: Gcore) -> None: + interface = client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_method_attach_with_all_params_overload_4(self, client: Gcore) -> None: + interface = client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="my-rfip-interface", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="reserved_fixed_ip", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_raw_response_attach_overload_4(self, client: Gcore) -> None: + response = client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_streaming_response_attach_overload_4(self, client: Gcore) -> None: + with client.cloud.instances.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_attach_overload_4(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) + + @parametrize + def test_method_detach(self, client: Gcore) -> None: + interface = client.cloud.instances.interfaces.detach( + instance_id="instance_id", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_raw_response_detach(self, client: Gcore) -> None: + response = client.cloud.instances.interfaces.with_raw_response.detach( + instance_id="instance_id", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + def test_streaming_response_detach(self, client: Gcore) -> None: + with client.cloud.instances.interfaces.with_streaming_response.detach( + instance_id="instance_id", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_detach(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.interfaces.with_raw_response.detach( + instance_id="", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) + + +class TestAsyncInterfaces: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.instances.interfaces.list( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(NetworkInterfaceList, interface, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.interfaces.with_raw_response.list( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = await response.parse() + assert_matches_type(NetworkInterfaceList, interface, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.interfaces.with_streaming_response.list( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = await response.parse() + assert_matches_type(NetworkInterfaceList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.interfaces.with_raw_response.list( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_attach_overload_1(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_method_attach_with_all_params_overload_1(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="interface_name", + ip_family="dual", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="external", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_raw_response_attach_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_streaming_response_attach_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_attach_overload_1(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_attach_overload_2(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_method_attach_with_all_params_overload_2(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="my-subnet-interface", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="subnet", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_raw_response_attach_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_streaming_response_attach_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_attach_overload_2(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + @parametrize + async def test_method_attach_overload_3(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_method_attach_with_all_params_overload_3(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="my-any-subnet-interface", + ip_family="dual", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="any_subnet", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_raw_response_attach_overload_3(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_streaming_response_attach_overload_3(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_attach_overload_3(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + ) + + @parametrize + async def test_method_attach_overload_4(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_method_attach_with_all_params_overload_4(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.instances.interfaces.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ddos_profile={ + "profile_template": 29, + "fields": [ + { + "base_field": 10, + "field_name": "field_name", + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template_name": "profile_template_name", + }, + interface_name="my-rfip-interface", + port_group=0, + security_groups=[ + {"id": "4536dba1-93b1-492e-b3df-270b6b9f3650"}, + {"id": "cee2ca1f-507a-4a31-b714-f6c1ffb4bdfa"}, + ], + type="reserved_fixed_ip", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_raw_response_attach_overload_4(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_streaming_response_attach_overload_4(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.interfaces.with_streaming_response.attach( + instance_id="instance_id", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_attach_overload_4(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.interfaces.with_raw_response.attach( + instance_id="", + project_id=0, + region_id=0, + port_id="59905c8e-2619-420a-b046-536096473370", + ) + + @parametrize + async def test_method_detach(self, async_client: AsyncGcore) -> None: + interface = await async_client.cloud.instances.interfaces.detach( + instance_id="instance_id", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_raw_response_detach(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.interfaces.with_raw_response.detach( + instance_id="instance_id", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + @parametrize + async def test_streaming_response_detach(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.interfaces.with_streaming_response.detach( + instance_id="instance_id", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + interface = await response.parse() + assert_matches_type(TaskIDList, interface, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_detach(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.interfaces.with_raw_response.detach( + instance_id="", + project_id=0, + region_id=0, + ip_address="192.168.123.20", + port_id="351b0dd7-ca09-431c-be53-935db3785067", + ) diff --git a/tests/api_resources/cloud/instances/test_metrics.py b/tests/api_resources/cloud/instances/test_metrics.py new file mode 100644 index 00000000..afa61520 --- /dev/null +++ b/tests/api_resources/cloud/instances/test_metrics.py @@ -0,0 +1,132 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.instances import MetricsList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMetrics: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + metric = client.cloud.instances.metrics.list( + instance_id="instance_id", + project_id=0, + region_id=0, + time_interval=6, + time_unit="day", + ) + assert_matches_type(MetricsList, metric, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.instances.metrics.with_raw_response.list( + instance_id="instance_id", + project_id=0, + region_id=0, + time_interval=6, + time_unit="day", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + metric = response.parse() + assert_matches_type(MetricsList, metric, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.instances.metrics.with_streaming_response.list( + instance_id="instance_id", + project_id=0, + region_id=0, + time_interval=6, + time_unit="day", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + metric = response.parse() + assert_matches_type(MetricsList, metric, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.metrics.with_raw_response.list( + instance_id="", + project_id=0, + region_id=0, + time_interval=6, + time_unit="day", + ) + + +class TestAsyncMetrics: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + metric = await async_client.cloud.instances.metrics.list( + instance_id="instance_id", + project_id=0, + region_id=0, + time_interval=6, + time_unit="day", + ) + assert_matches_type(MetricsList, metric, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.metrics.with_raw_response.list( + instance_id="instance_id", + project_id=0, + region_id=0, + time_interval=6, + time_unit="day", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + metric = await response.parse() + assert_matches_type(MetricsList, metric, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.metrics.with_streaming_response.list( + instance_id="instance_id", + project_id=0, + region_id=0, + time_interval=6, + time_unit="day", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + metric = await response.parse() + assert_matches_type(MetricsList, metric, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.metrics.with_raw_response.list( + instance_id="", + project_id=0, + region_id=0, + time_interval=6, + time_unit="day", + ) diff --git a/tests/api_resources/cloud/k8s/__init__.py b/tests/api_resources/cloud/k8s/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/k8s/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/k8s/clusters/__init__.py b/tests/api_resources/cloud/k8s/clusters/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/k8s/clusters/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/k8s/clusters/pools/__init__.py b/tests/api_resources/cloud/k8s/clusters/pools/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/k8s/clusters/pools/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/k8s/clusters/pools/test_nodes.py b/tests/api_resources/cloud/k8s/clusters/pools/test_nodes.py new file mode 100644 index 00000000..db1bce7d --- /dev/null +++ b/tests/api_resources/cloud/k8s/clusters/pools/test_nodes.py @@ -0,0 +1,306 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import InstanceList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestNodes: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + node = client.cloud.k8s.clusters.pools.nodes.list( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + assert_matches_type(InstanceList, node, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + node = client.cloud.k8s.clusters.pools.nodes.list( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + with_ddos=False, + ) + assert_matches_type(InstanceList, node, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.pools.nodes.with_raw_response.list( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + node = response.parse() + assert_matches_type(InstanceList, node, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.pools.nodes.with_streaming_response.list( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + node = response.parse() + assert_matches_type(InstanceList, node, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.pools.nodes.with_raw_response.list( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_name` but received ''"): + client.cloud.k8s.clusters.pools.nodes.with_raw_response.list( + pool_name="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + node = client.cloud.k8s.clusters.pools.nodes.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + pool_name="my-pool", + ) + assert node is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.pools.nodes.with_raw_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + pool_name="my-pool", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + node = response.parse() + assert node is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.pools.nodes.with_streaming_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + pool_name="my-pool", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + node = response.parse() + assert node is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.pools.nodes.with_raw_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="", + pool_name="my-pool", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_name` but received ''"): + client.cloud.k8s.clusters.pools.nodes.with_raw_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + pool_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.k8s.clusters.pools.nodes.with_raw_response.delete( + instance_id="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + pool_name="my-pool", + ) + + +class TestAsyncNodes: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + node = await async_client.cloud.k8s.clusters.pools.nodes.list( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + assert_matches_type(InstanceList, node, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + node = await async_client.cloud.k8s.clusters.pools.nodes.list( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + with_ddos=False, + ) + assert_matches_type(InstanceList, node, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.pools.nodes.with_raw_response.list( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + node = await response.parse() + assert_matches_type(InstanceList, node, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.pools.nodes.with_streaming_response.list( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + node = await response.parse() + assert_matches_type(InstanceList, node, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.nodes.with_raw_response.list( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.nodes.with_raw_response.list( + pool_name="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + node = await async_client.cloud.k8s.clusters.pools.nodes.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + pool_name="my-pool", + ) + assert node is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.pools.nodes.with_raw_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + pool_name="my-pool", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + node = await response.parse() + assert node is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.pools.nodes.with_streaming_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + pool_name="my-pool", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + node = await response.parse() + assert node is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.nodes.with_raw_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="", + pool_name="my-pool", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.nodes.with_raw_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + pool_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.k8s.clusters.pools.nodes.with_raw_response.delete( + instance_id="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + pool_name="my-pool", + ) diff --git a/tests/api_resources/cloud/k8s/clusters/test_nodes.py b/tests/api_resources/cloud/k8s/clusters/test_nodes.py new file mode 100644 index 00000000..7e5c41c3 --- /dev/null +++ b/tests/api_resources/cloud/k8s/clusters/test_nodes.py @@ -0,0 +1,252 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import InstanceList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestNodes: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + node = client.cloud.k8s.clusters.nodes.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(InstanceList, node, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + node = client.cloud.k8s.clusters.nodes.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + with_ddos=False, + ) + assert_matches_type(InstanceList, node, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.nodes.with_raw_response.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + node = response.parse() + assert_matches_type(InstanceList, node, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.nodes.with_streaming_response.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + node = response.parse() + assert_matches_type(InstanceList, node, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.nodes.with_raw_response.list( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + node = client.cloud.k8s.clusters.nodes.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + assert node is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.nodes.with_raw_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + node = response.parse() + assert node is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.nodes.with_streaming_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + node = response.parse() + assert node is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.nodes.with_raw_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.k8s.clusters.nodes.with_raw_response.delete( + instance_id="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + +class TestAsyncNodes: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + node = await async_client.cloud.k8s.clusters.nodes.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(InstanceList, node, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + node = await async_client.cloud.k8s.clusters.nodes.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + with_ddos=False, + ) + assert_matches_type(InstanceList, node, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.nodes.with_raw_response.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + node = await response.parse() + assert_matches_type(InstanceList, node, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.nodes.with_streaming_response.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + node = await response.parse() + assert_matches_type(InstanceList, node, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.nodes.with_raw_response.list( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + node = await async_client.cloud.k8s.clusters.nodes.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + assert node is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.nodes.with_raw_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + node = await response.parse() + assert node is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.nodes.with_streaming_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + node = await response.parse() + assert node is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.nodes.with_raw_response.delete( + instance_id="550e8400-e29b-41d4-a716-446655440000", + project_id=1, + region_id=7, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.k8s.clusters.nodes.with_raw_response.delete( + instance_id="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) diff --git a/tests/api_resources/cloud/k8s/clusters/test_pools.py b/tests/api_resources/cloud/k8s/clusters/test_pools.py new file mode 100644 index 00000000..b928939a --- /dev/null +++ b/tests/api_resources/cloud/k8s/clusters/test_pools.py @@ -0,0 +1,891 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import TaskIDList +from gcore.types.cloud.k8s.clusters import ( + K8SClusterPool, + K8SClusterPoolList, + K8SClusterPoolQuota, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPools: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.create( + cluster_name="my-cluster", + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + min_node_count=3, + name="my-pool", + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.create( + cluster_name="my-cluster", + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + min_node_count=3, + name="my-pool", + auto_healing_enabled=True, + boot_volume_size=50, + boot_volume_type="ssd_hiiops", + crio_config={"default-ulimits": "nofile=1024:2048"}, + is_public_ipv4=True, + kubelet_config={"podMaxPids": "4096"}, + labels={"my-label": "foo"}, + max_node_count=5, + servergroup_policy="affinity", + taints={"my-taint": "bar:NoSchedule"}, + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.pools.with_raw_response.create( + cluster_name="my-cluster", + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + min_node_count=3, + name="my-pool", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.pools.with_streaming_response.create( + cluster_name="my-cluster", + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + min_node_count=3, + name="my-pool", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.pools.with_raw_response.create( + cluster_name="", + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + min_node_count=3, + name="my-pool", + ) + + @parametrize + def test_method_update(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.update( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.update( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + auto_healing_enabled=True, + labels={"my-label": "foo"}, + max_node_count=3, + min_node_count=1, + node_count=2, + taints={"my-taint": "bar:NoSchedule"}, + ) + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.pools.with_raw_response.update( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = response.parse() + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.pools.with_streaming_response.update( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = response.parse() + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.pools.with_raw_response.update( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_name` but received ''"): + client.cloud.k8s.clusters.pools.with_raw_response.update( + pool_name="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(K8SClusterPoolList, pool, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.pools.with_raw_response.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = response.parse() + assert_matches_type(K8SClusterPoolList, pool, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.pools.with_streaming_response.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = response.parse() + assert_matches_type(K8SClusterPoolList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.pools.with_raw_response.list( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.delete( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.pools.with_raw_response.delete( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.pools.with_streaming_response.delete( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.pools.with_raw_response.delete( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_name` but received ''"): + client.cloud.k8s.clusters.pools.with_raw_response.delete( + pool_name="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + @parametrize + def test_method_check_quota(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.check_quota( + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + ) + assert_matches_type(K8SClusterPoolQuota, pool, path=["response"]) + + @parametrize + def test_method_check_quota_with_all_params(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.check_quota( + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + boot_volume_size=50, + max_node_count=5, + min_node_count=3, + name="test", + node_count=5, + servergroup_policy="anti-affinity", + ) + assert_matches_type(K8SClusterPoolQuota, pool, path=["response"]) + + @parametrize + def test_raw_response_check_quota(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.pools.with_raw_response.check_quota( + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = response.parse() + assert_matches_type(K8SClusterPoolQuota, pool, path=["response"]) + + @parametrize + def test_streaming_response_check_quota(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.pools.with_streaming_response.check_quota( + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = response.parse() + assert_matches_type(K8SClusterPoolQuota, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.get( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.pools.with_raw_response.get( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = response.parse() + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.pools.with_streaming_response.get( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = response.parse() + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.pools.with_raw_response.get( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_name` but received ''"): + client.cloud.k8s.clusters.pools.with_raw_response.get( + pool_name="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + @parametrize + def test_method_resize(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.resize( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + node_count=2, + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_raw_response_resize(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.pools.with_raw_response.resize( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + node_count=2, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_streaming_response_resize(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.pools.with_streaming_response.resize( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + node_count=2, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_resize(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.pools.with_raw_response.resize( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="", + node_count=2, + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_name` but received ''"): + client.cloud.k8s.clusters.pools.with_raw_response.resize( + pool_name="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + node_count=2, + ) + + +class TestAsyncPools: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.create( + cluster_name="my-cluster", + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + min_node_count=3, + name="my-pool", + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.create( + cluster_name="my-cluster", + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + min_node_count=3, + name="my-pool", + auto_healing_enabled=True, + boot_volume_size=50, + boot_volume_type="ssd_hiiops", + crio_config={"default-ulimits": "nofile=1024:2048"}, + is_public_ipv4=True, + kubelet_config={"podMaxPids": "4096"}, + labels={"my-label": "foo"}, + max_node_count=5, + servergroup_policy="affinity", + taints={"my-taint": "bar:NoSchedule"}, + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.pools.with_raw_response.create( + cluster_name="my-cluster", + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + min_node_count=3, + name="my-pool", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = await response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.pools.with_streaming_response.create( + cluster_name="my-cluster", + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + min_node_count=3, + name="my-pool", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = await response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.with_raw_response.create( + cluster_name="", + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + min_node_count=3, + name="my-pool", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.update( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.update( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + auto_healing_enabled=True, + labels={"my-label": "foo"}, + max_node_count=3, + min_node_count=1, + node_count=2, + taints={"my-taint": "bar:NoSchedule"}, + ) + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.pools.with_raw_response.update( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = await response.parse() + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.pools.with_streaming_response.update( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = await response.parse() + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.with_raw_response.update( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.with_raw_response.update( + pool_name="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(K8SClusterPoolList, pool, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.pools.with_raw_response.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = await response.parse() + assert_matches_type(K8SClusterPoolList, pool, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.pools.with_streaming_response.list( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = await response.parse() + assert_matches_type(K8SClusterPoolList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.with_raw_response.list( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.delete( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.pools.with_raw_response.delete( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = await response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.pools.with_streaming_response.delete( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = await response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.with_raw_response.delete( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.with_raw_response.delete( + pool_name="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + @parametrize + async def test_method_check_quota(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.check_quota( + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + ) + assert_matches_type(K8SClusterPoolQuota, pool, path=["response"]) + + @parametrize + async def test_method_check_quota_with_all_params(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.check_quota( + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + boot_volume_size=50, + max_node_count=5, + min_node_count=3, + name="test", + node_count=5, + servergroup_policy="anti-affinity", + ) + assert_matches_type(K8SClusterPoolQuota, pool, path=["response"]) + + @parametrize + async def test_raw_response_check_quota(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.pools.with_raw_response.check_quota( + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = await response.parse() + assert_matches_type(K8SClusterPoolQuota, pool, path=["response"]) + + @parametrize + async def test_streaming_response_check_quota(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.pools.with_streaming_response.check_quota( + project_id=1, + region_id=7, + flavor_id="g1-standard-1-2", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = await response.parse() + assert_matches_type(K8SClusterPoolQuota, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.get( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.pools.with_raw_response.get( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = await response.parse() + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.pools.with_streaming_response.get( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = await response.parse() + assert_matches_type(K8SClusterPool, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.with_raw_response.get( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.with_raw_response.get( + pool_name="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + ) + + @parametrize + async def test_method_resize(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.resize( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + node_count=2, + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_raw_response_resize(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.pools.with_raw_response.resize( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + node_count=2, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = await response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_streaming_response_resize(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.pools.with_streaming_response.resize( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="my-cluster", + node_count=2, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = await response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_resize(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.with_raw_response.resize( + pool_name="my-pool", + project_id=1, + region_id=7, + cluster_name="", + node_count=2, + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_name` but received ''"): + await async_client.cloud.k8s.clusters.pools.with_raw_response.resize( + pool_name="", + project_id=1, + region_id=7, + cluster_name="my-cluster", + node_count=2, + ) diff --git a/tests/api_resources/cloud/k8s/test_clusters.py b/tests/api_resources/cloud/k8s/test_clusters.py new file mode 100644 index 00000000..1fd9c956 --- /dev/null +++ b/tests/api_resources/cloud/k8s/test_clusters.py @@ -0,0 +1,1200 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import TaskIDList, K8SClusterVersionList +from gcore.types.cloud.k8s import ( + K8SCluster, + K8SClusterList, + K8SClusterKubeconfig, + K8SClusterCertificate, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestClusters: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.create( + project_id=1, + region_id=7, + keypair="some_keypair", + name="string", + pools=[ + { + "flavor_id": "g1-standard-1-2", + "min_node_count": 3, + "name": "my-pool", + } + ], + version="1.28.1", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.create( + project_id=1, + region_id=7, + keypair="some_keypair", + name="string", + pools=[ + { + "flavor_id": "g1-standard-1-2", + "min_node_count": 3, + "name": "my-pool", + "auto_healing_enabled": True, + "boot_volume_size": 50, + "boot_volume_type": "ssd_hiiops", + "crio_config": {"default-ulimits": "nofile=1024:2048"}, + "is_public_ipv4": True, + "kubelet_config": {"podMaxPids": "4096"}, + "labels": {"my-label": "foo"}, + "max_node_count": 5, + "servergroup_policy": "affinity", + "taints": {"my-taint": "bar:NoSchedule"}, + } + ], + version="1.28.1", + add_ons={ + "slurm": { + "enabled": True, + "file_share_id": "cbc94d0e-06c6-4d12-9e86-9782ba14fc8c", + "ssh_key_ids": ["25735292-bd97-44b0-a1af-d7eab876261d", "efc01f3a-35b9-4385-89f9-e38439093ee7"], + "worker_count": 2, + } + }, + authentication={ + "oidc": { + "client_id": "kubernetes", + "groups_claim": "groups", + "groups_prefix": "oidc:", + "issuer_url": "https://accounts.provider.example", + "required_claims": {"claim": "value"}, + "signing_algs": ["RS256", "RS512"], + "username_claim": "sub", + "username_prefix": "oidc:", + } + }, + autoscaler_config={"scale-down-unneeded-time": "5m"}, + cni={ + "cilium": { + "encryption": True, + "hubble_relay": True, + "hubble_ui": True, + "lb_acceleration": True, + "lb_mode": "snat", + "mask_size": 24, + "mask_size_v6": 120, + "routing_mode": "tunnel", + "tunnel": "geneve", + }, + "provider": "cilium", + }, + csi={"nfs": {"vast_enabled": True}}, + ddos_profile={ + "enabled": True, + "fields": [ + { + "base_field": 10, + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template": 29, + "profile_template_name": "profile_template_name", + }, + fixed_network="3fa85f64-5717-4562-b3fc-2c963f66afa6", + fixed_subnet="3fa85f64-5717-4562-b3fc-2c963f66afa6", + is_ipv6=True, + logging={ + "destination_region_id": 1, + "enabled": True, + "retention_policy": {"period": 45}, + "topic_name": "my-log-name", + }, + pods_ip_pool="172.16.0.0/18", + pods_ipv6_pool="2a03:90c0:88:393::/64", + services_ip_pool="172.24.0.0/18", + services_ipv6_pool="2a03:90c0:88:381::/108", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.with_raw_response.create( + project_id=1, + region_id=7, + keypair="some_keypair", + name="string", + pools=[ + { + "flavor_id": "g1-standard-1-2", + "min_node_count": 3, + "name": "my-pool", + } + ], + version="1.28.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.with_streaming_response.create( + project_id=1, + region_id=7, + keypair="some_keypair", + name="string", + pools=[ + { + "flavor_id": "g1-standard-1-2", + "min_node_count": 3, + "name": "my-pool", + } + ], + version="1.28.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.update( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.update( + cluster_name="my-cluster", + project_id=1, + region_id=7, + add_ons={ + "slurm": { + "enabled": True, + "file_share_id": "cbc94d0e-06c6-4d12-9e86-9782ba14fc8c", + "ssh_key_ids": ["25735292-bd97-44b0-a1af-d7eab876261d", "efc01f3a-35b9-4385-89f9-e38439093ee7"], + "worker_count": 2, + } + }, + authentication={ + "oidc": { + "client_id": "kubernetes", + "groups_claim": "groups", + "groups_prefix": "oidc:", + "issuer_url": "https://accounts.provider.example", + "required_claims": {"claim": "value"}, + "signing_algs": ["RS256", "RS512"], + "username_claim": "sub", + "username_prefix": "oidc:", + } + }, + autoscaler_config={"scale-down-unneeded-time": "5m"}, + cni={ + "cilium": { + "encryption": True, + "hubble_relay": True, + "hubble_ui": True, + "lb_acceleration": True, + "lb_mode": "snat", + "mask_size": 24, + "mask_size_v6": 120, + "routing_mode": "tunnel", + "tunnel": "geneve", + }, + "provider": "cilium", + }, + ddos_profile={ + "enabled": True, + "fields": [ + { + "base_field": 10, + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template": 29, + "profile_template_name": "profile_template_name", + }, + logging={ + "destination_region_id": 1, + "enabled": True, + "retention_policy": {"period": 45}, + "topic_name": "my-log-name", + }, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.with_raw_response.update( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.with_streaming_response.update( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.with_raw_response.update( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.list( + project_id=1, + region_id=7, + ) + assert_matches_type(K8SClusterList, cluster, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(K8SClusterList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(K8SClusterList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.delete( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_method_delete_with_all_params(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.delete( + cluster_name="my-cluster", + project_id=1, + region_id=7, + volumes="550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.with_raw_response.delete( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.with_streaming_response.delete( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.with_raw_response.delete( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.get( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(K8SCluster, cluster, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.with_raw_response.get( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(K8SCluster, cluster, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.with_streaming_response.get( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(K8SCluster, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.with_raw_response.get( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_get_certificate(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.get_certificate( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(K8SClusterCertificate, cluster, path=["response"]) + + @parametrize + def test_raw_response_get_certificate(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.with_raw_response.get_certificate( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(K8SClusterCertificate, cluster, path=["response"]) + + @parametrize + def test_streaming_response_get_certificate(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.with_streaming_response.get_certificate( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(K8SClusterCertificate, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_certificate(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.with_raw_response.get_certificate( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_get_kubeconfig(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.get_kubeconfig( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(K8SClusterKubeconfig, cluster, path=["response"]) + + @parametrize + def test_raw_response_get_kubeconfig(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.with_raw_response.get_kubeconfig( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(K8SClusterKubeconfig, cluster, path=["response"]) + + @parametrize + def test_streaming_response_get_kubeconfig(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.with_streaming_response.get_kubeconfig( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(K8SClusterKubeconfig, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_kubeconfig(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.with_raw_response.get_kubeconfig( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_list_versions_for_upgrade(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.list_versions_for_upgrade( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(K8SClusterVersionList, cluster, path=["response"]) + + @parametrize + def test_raw_response_list_versions_for_upgrade(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.with_raw_response.list_versions_for_upgrade( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(K8SClusterVersionList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_list_versions_for_upgrade(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.with_streaming_response.list_versions_for_upgrade( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(K8SClusterVersionList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list_versions_for_upgrade(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.with_raw_response.list_versions_for_upgrade( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_upgrade(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.upgrade( + cluster_name="my-cluster", + project_id=1, + region_id=7, + version="v1.28.1", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_raw_response_upgrade(self, client: Gcore) -> None: + response = client.cloud.k8s.clusters.with_raw_response.upgrade( + cluster_name="my-cluster", + project_id=1, + region_id=7, + version="v1.28.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + def test_streaming_response_upgrade(self, client: Gcore) -> None: + with client.cloud.k8s.clusters.with_streaming_response.upgrade( + cluster_name="my-cluster", + project_id=1, + region_id=7, + version="v1.28.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_upgrade(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + client.cloud.k8s.clusters.with_raw_response.upgrade( + cluster_name="", + project_id=1, + region_id=7, + version="v1.28.1", + ) + + +class TestAsyncClusters: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.create( + project_id=1, + region_id=7, + keypair="some_keypair", + name="string", + pools=[ + { + "flavor_id": "g1-standard-1-2", + "min_node_count": 3, + "name": "my-pool", + } + ], + version="1.28.1", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.create( + project_id=1, + region_id=7, + keypair="some_keypair", + name="string", + pools=[ + { + "flavor_id": "g1-standard-1-2", + "min_node_count": 3, + "name": "my-pool", + "auto_healing_enabled": True, + "boot_volume_size": 50, + "boot_volume_type": "ssd_hiiops", + "crio_config": {"default-ulimits": "nofile=1024:2048"}, + "is_public_ipv4": True, + "kubelet_config": {"podMaxPids": "4096"}, + "labels": {"my-label": "foo"}, + "max_node_count": 5, + "servergroup_policy": "affinity", + "taints": {"my-taint": "bar:NoSchedule"}, + } + ], + version="1.28.1", + add_ons={ + "slurm": { + "enabled": True, + "file_share_id": "cbc94d0e-06c6-4d12-9e86-9782ba14fc8c", + "ssh_key_ids": ["25735292-bd97-44b0-a1af-d7eab876261d", "efc01f3a-35b9-4385-89f9-e38439093ee7"], + "worker_count": 2, + } + }, + authentication={ + "oidc": { + "client_id": "kubernetes", + "groups_claim": "groups", + "groups_prefix": "oidc:", + "issuer_url": "https://accounts.provider.example", + "required_claims": {"claim": "value"}, + "signing_algs": ["RS256", "RS512"], + "username_claim": "sub", + "username_prefix": "oidc:", + } + }, + autoscaler_config={"scale-down-unneeded-time": "5m"}, + cni={ + "cilium": { + "encryption": True, + "hubble_relay": True, + "hubble_ui": True, + "lb_acceleration": True, + "lb_mode": "snat", + "mask_size": 24, + "mask_size_v6": 120, + "routing_mode": "tunnel", + "tunnel": "geneve", + }, + "provider": "cilium", + }, + csi={"nfs": {"vast_enabled": True}}, + ddos_profile={ + "enabled": True, + "fields": [ + { + "base_field": 10, + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template": 29, + "profile_template_name": "profile_template_name", + }, + fixed_network="3fa85f64-5717-4562-b3fc-2c963f66afa6", + fixed_subnet="3fa85f64-5717-4562-b3fc-2c963f66afa6", + is_ipv6=True, + logging={ + "destination_region_id": 1, + "enabled": True, + "retention_policy": {"period": 45}, + "topic_name": "my-log-name", + }, + pods_ip_pool="172.16.0.0/18", + pods_ipv6_pool="2a03:90c0:88:393::/64", + services_ip_pool="172.24.0.0/18", + services_ipv6_pool="2a03:90c0:88:381::/108", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.with_raw_response.create( + project_id=1, + region_id=7, + keypair="some_keypair", + name="string", + pools=[ + { + "flavor_id": "g1-standard-1-2", + "min_node_count": 3, + "name": "my-pool", + } + ], + version="1.28.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.with_streaming_response.create( + project_id=1, + region_id=7, + keypair="some_keypair", + name="string", + pools=[ + { + "flavor_id": "g1-standard-1-2", + "min_node_count": 3, + "name": "my-pool", + } + ], + version="1.28.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.update( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.update( + cluster_name="my-cluster", + project_id=1, + region_id=7, + add_ons={ + "slurm": { + "enabled": True, + "file_share_id": "cbc94d0e-06c6-4d12-9e86-9782ba14fc8c", + "ssh_key_ids": ["25735292-bd97-44b0-a1af-d7eab876261d", "efc01f3a-35b9-4385-89f9-e38439093ee7"], + "worker_count": 2, + } + }, + authentication={ + "oidc": { + "client_id": "kubernetes", + "groups_claim": "groups", + "groups_prefix": "oidc:", + "issuer_url": "https://accounts.provider.example", + "required_claims": {"claim": "value"}, + "signing_algs": ["RS256", "RS512"], + "username_claim": "sub", + "username_prefix": "oidc:", + } + }, + autoscaler_config={"scale-down-unneeded-time": "5m"}, + cni={ + "cilium": { + "encryption": True, + "hubble_relay": True, + "hubble_ui": True, + "lb_acceleration": True, + "lb_mode": "snat", + "mask_size": 24, + "mask_size_v6": 120, + "routing_mode": "tunnel", + "tunnel": "geneve", + }, + "provider": "cilium", + }, + ddos_profile={ + "enabled": True, + "fields": [ + { + "base_field": 10, + "field_value": [45046, 45047], + "value": None, + } + ], + "profile_template": 29, + "profile_template_name": "profile_template_name", + }, + logging={ + "destination_region_id": 1, + "enabled": True, + "retention_policy": {"period": 45}, + "topic_name": "my-log-name", + }, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.with_raw_response.update( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.with_streaming_response.update( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.with_raw_response.update( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.list( + project_id=1, + region_id=7, + ) + assert_matches_type(K8SClusterList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(K8SClusterList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(K8SClusterList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.delete( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.delete( + cluster_name="my-cluster", + project_id=1, + region_id=7, + volumes="550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.with_raw_response.delete( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.with_streaming_response.delete( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.with_raw_response.delete( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.get( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(K8SCluster, cluster, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.with_raw_response.get( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(K8SCluster, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.with_streaming_response.get( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(K8SCluster, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.with_raw_response.get( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_get_certificate(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.get_certificate( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(K8SClusterCertificate, cluster, path=["response"]) + + @parametrize + async def test_raw_response_get_certificate(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.with_raw_response.get_certificate( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(K8SClusterCertificate, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_get_certificate(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.with_streaming_response.get_certificate( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(K8SClusterCertificate, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_certificate(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.with_raw_response.get_certificate( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_get_kubeconfig(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.get_kubeconfig( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(K8SClusterKubeconfig, cluster, path=["response"]) + + @parametrize + async def test_raw_response_get_kubeconfig(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.with_raw_response.get_kubeconfig( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(K8SClusterKubeconfig, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_get_kubeconfig(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.with_streaming_response.get_kubeconfig( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(K8SClusterKubeconfig, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_kubeconfig(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.with_raw_response.get_kubeconfig( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_list_versions_for_upgrade(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.list_versions_for_upgrade( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + assert_matches_type(K8SClusterVersionList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_list_versions_for_upgrade(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.with_raw_response.list_versions_for_upgrade( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(K8SClusterVersionList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_list_versions_for_upgrade(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.with_streaming_response.list_versions_for_upgrade( + cluster_name="my-cluster", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(K8SClusterVersionList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list_versions_for_upgrade(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.with_raw_response.list_versions_for_upgrade( + cluster_name="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_upgrade(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.upgrade( + cluster_name="my-cluster", + project_id=1, + region_id=7, + version="v1.28.1", + ) + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_raw_response_upgrade(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.clusters.with_raw_response.upgrade( + cluster_name="my-cluster", + project_id=1, + region_id=7, + version="v1.28.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + @parametrize + async def test_streaming_response_upgrade(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.clusters.with_streaming_response.upgrade( + cluster_name="my-cluster", + project_id=1, + region_id=7, + version="v1.28.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(TaskIDList, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_upgrade(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `cluster_name` but received ''"): + await async_client.cloud.k8s.clusters.with_raw_response.upgrade( + cluster_name="", + project_id=1, + region_id=7, + version="v1.28.1", + ) diff --git a/tests/api_resources/cloud/k8s/test_flavors.py b/tests/api_resources/cloud/k8s/test_flavors.py new file mode 100644 index 00000000..898e9a30 --- /dev/null +++ b/tests/api_resources/cloud/k8s/test_flavors.py @@ -0,0 +1,114 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import BaremetalFlavorList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFlavors: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + flavor = client.cloud.k8s.flavors.list( + project_id=1, + region_id=7, + ) + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + flavor = client.cloud.k8s.flavors.list( + project_id=1, + region_id=7, + exclude_gpu=False, + include_capacity=False, + include_prices=False, + ) + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.k8s.flavors.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = response.parse() + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.k8s.flavors.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = response.parse() + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncFlavors: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.k8s.flavors.list( + project_id=1, + region_id=7, + ) + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.k8s.flavors.list( + project_id=1, + region_id=7, + exclude_gpu=False, + include_capacity=False, + include_prices=False, + ) + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.flavors.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = await response.parse() + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.flavors.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = await response.parse() + assert_matches_type(BaremetalFlavorList, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/load_balancers/__init__.py b/tests/api_resources/cloud/load_balancers/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/load_balancers/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/load_balancers/l7_policies/__init__.py b/tests/api_resources/cloud/load_balancers/l7_policies/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/load_balancers/l7_policies/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/load_balancers/l7_policies/test_rules.py b/tests/api_resources/cloud/load_balancers/l7_policies/test_rules.py new file mode 100644 index 00000000..2538e125 --- /dev/null +++ b/tests/api_resources/cloud/load_balancers/l7_policies/test_rules.py @@ -0,0 +1,652 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import TaskIDList, LoadBalancerL7Rule, LoadBalancerL7RuleList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRules: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + rule = client.cloud.load_balancers.l7_policies.rules.create( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + compare_type="REGEX", + type="PATH", + value="/images*", + ) + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + rule = client.cloud.load_balancers.l7_policies.rules.create( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + compare_type="REGEX", + type="PATH", + value="/images*", + invert=True, + key="the name of the cookie or header to evaluate.", + tags=["test_tag_1", "test_tag_2"], + ) + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.rules.with_raw_response.create( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + compare_type="REGEX", + type="PATH", + value="/images*", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.rules.with_streaming_response.create( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + compare_type="REGEX", + type="PATH", + value="/images*", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert_matches_type(TaskIDList, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + client.cloud.load_balancers.l7_policies.rules.with_raw_response.create( + l7policy_id="", + project_id=1, + region_id=1, + compare_type="REGEX", + type="PATH", + value="/images*", + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + rule = client.cloud.load_balancers.l7_policies.rules.list( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerL7RuleList, rule, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.rules.with_raw_response.list( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert_matches_type(LoadBalancerL7RuleList, rule, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.rules.with_streaming_response.list( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert_matches_type(LoadBalancerL7RuleList, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + client.cloud.load_balancers.l7_policies.rules.with_raw_response.list( + l7policy_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + rule = client.cloud.load_balancers.l7_policies.rules.delete( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.rules.with_raw_response.delete( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.rules.with_streaming_response.delete( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert_matches_type(TaskIDList, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + client.cloud.load_balancers.l7_policies.rules.with_raw_response.delete( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7rule_id` but received ''"): + client.cloud.load_balancers.l7_policies.rules.with_raw_response.delete( + l7rule_id="", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + rule = client.cloud.load_balancers.l7_policies.rules.get( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + assert_matches_type(LoadBalancerL7Rule, rule, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.rules.with_raw_response.get( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert_matches_type(LoadBalancerL7Rule, rule, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.rules.with_streaming_response.get( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert_matches_type(LoadBalancerL7Rule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + client.cloud.load_balancers.l7_policies.rules.with_raw_response.get( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7rule_id` but received ''"): + client.cloud.load_balancers.l7_policies.rules.with_raw_response.get( + l7rule_id="", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + rule = client.cloud.load_balancers.l7_policies.rules.replace( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + compare_type="REGEX", + ) + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + rule = client.cloud.load_balancers.l7_policies.rules.replace( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + compare_type="REGEX", + invert=True, + key="the name of the cookie or header to evaluate.", + tags=["test_tag_1", "test_tag_2"], + type="PATH", + value="/images*", + ) + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.rules.with_raw_response.replace( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + compare_type="REGEX", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.rules.with_streaming_response.replace( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + compare_type="REGEX", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert_matches_type(TaskIDList, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_replace(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + client.cloud.load_balancers.l7_policies.rules.with_raw_response.replace( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="", + compare_type="REGEX", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7rule_id` but received ''"): + client.cloud.load_balancers.l7_policies.rules.with_raw_response.replace( + l7rule_id="", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + compare_type="REGEX", + ) + + +class TestAsyncRules: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + rule = await async_client.cloud.load_balancers.l7_policies.rules.create( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + compare_type="REGEX", + type="PATH", + value="/images*", + ) + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + rule = await async_client.cloud.load_balancers.l7_policies.rules.create( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + compare_type="REGEX", + type="PATH", + value="/images*", + invert=True, + key="the name of the cookie or header to evaluate.", + tags=["test_tag_1", "test_tag_2"], + ) + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.rules.with_raw_response.create( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + compare_type="REGEX", + type="PATH", + value="/images*", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.rules.with_streaming_response.create( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + compare_type="REGEX", + type="PATH", + value="/images*", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert_matches_type(TaskIDList, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.rules.with_raw_response.create( + l7policy_id="", + project_id=1, + region_id=1, + compare_type="REGEX", + type="PATH", + value="/images*", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + rule = await async_client.cloud.load_balancers.l7_policies.rules.list( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerL7RuleList, rule, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.rules.with_raw_response.list( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert_matches_type(LoadBalancerL7RuleList, rule, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.rules.with_streaming_response.list( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert_matches_type(LoadBalancerL7RuleList, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.rules.with_raw_response.list( + l7policy_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + rule = await async_client.cloud.load_balancers.l7_policies.rules.delete( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.rules.with_raw_response.delete( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.rules.with_streaming_response.delete( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert_matches_type(TaskIDList, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.rules.with_raw_response.delete( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7rule_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.rules.with_raw_response.delete( + l7rule_id="", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + rule = await async_client.cloud.load_balancers.l7_policies.rules.get( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + assert_matches_type(LoadBalancerL7Rule, rule, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.rules.with_raw_response.get( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert_matches_type(LoadBalancerL7Rule, rule, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.rules.with_streaming_response.get( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert_matches_type(LoadBalancerL7Rule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.rules.with_raw_response.get( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7rule_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.rules.with_raw_response.get( + l7rule_id="", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + rule = await async_client.cloud.load_balancers.l7_policies.rules.replace( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + compare_type="REGEX", + ) + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + rule = await async_client.cloud.load_balancers.l7_policies.rules.replace( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + compare_type="REGEX", + invert=True, + key="the name of the cookie or header to evaluate.", + tags=["test_tag_1", "test_tag_2"], + type="PATH", + value="/images*", + ) + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.rules.with_raw_response.replace( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + compare_type="REGEX", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert_matches_type(TaskIDList, rule, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.rules.with_streaming_response.replace( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + compare_type="REGEX", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert_matches_type(TaskIDList, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_replace(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.rules.with_raw_response.replace( + l7rule_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + l7policy_id="", + compare_type="REGEX", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7rule_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.rules.with_raw_response.replace( + l7rule_id="", + project_id=1, + region_id=1, + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + compare_type="REGEX", + ) diff --git a/tests/api_resources/cloud/load_balancers/pools/__init__.py b/tests/api_resources/cloud/load_balancers/pools/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/load_balancers/pools/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/load_balancers/pools/test_health_monitors.py b/tests/api_resources/cloud/load_balancers/pools/test_health_monitors.py new file mode 100644 index 00000000..71eb353d --- /dev/null +++ b/tests/api_resources/cloud/load_balancers/pools/test_health_monitors.py @@ -0,0 +1,276 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import TaskIDList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestHealthMonitors: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + health_monitor = client.cloud.load_balancers.pools.health_monitors.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + delay=10, + max_retries=2, + api_timeout=5, + type="HTTP", + ) + assert_matches_type(TaskIDList, health_monitor, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + health_monitor = client.cloud.load_balancers.pools.health_monitors.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + delay=10, + max_retries=2, + api_timeout=5, + type="HTTP", + admin_state_up=True, + expected_codes="200,301,302", + http_method="CONNECT", + max_retries_down=2, + url_path="/", + ) + assert_matches_type(TaskIDList, health_monitor, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.load_balancers.pools.health_monitors.with_raw_response.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + delay=10, + max_retries=2, + api_timeout=5, + type="HTTP", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + health_monitor = response.parse() + assert_matches_type(TaskIDList, health_monitor, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.load_balancers.pools.health_monitors.with_streaming_response.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + delay=10, + max_retries=2, + api_timeout=5, + type="HTTP", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + health_monitor = response.parse() + assert_matches_type(TaskIDList, health_monitor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + client.cloud.load_balancers.pools.health_monitors.with_raw_response.create( + pool_id="", + project_id=1, + region_id=1, + delay=10, + max_retries=2, + api_timeout=5, + type="HTTP", + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + health_monitor = client.cloud.load_balancers.pools.health_monitors.delete( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert health_monitor is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.load_balancers.pools.health_monitors.with_raw_response.delete( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + health_monitor = response.parse() + assert health_monitor is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.load_balancers.pools.health_monitors.with_streaming_response.delete( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + health_monitor = response.parse() + assert health_monitor is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + client.cloud.load_balancers.pools.health_monitors.with_raw_response.delete( + pool_id="", + project_id=1, + region_id=1, + ) + + +class TestAsyncHealthMonitors: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + health_monitor = await async_client.cloud.load_balancers.pools.health_monitors.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + delay=10, + max_retries=2, + api_timeout=5, + type="HTTP", + ) + assert_matches_type(TaskIDList, health_monitor, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + health_monitor = await async_client.cloud.load_balancers.pools.health_monitors.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + delay=10, + max_retries=2, + api_timeout=5, + type="HTTP", + admin_state_up=True, + expected_codes="200,301,302", + http_method="CONNECT", + max_retries_down=2, + url_path="/", + ) + assert_matches_type(TaskIDList, health_monitor, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.pools.health_monitors.with_raw_response.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + delay=10, + max_retries=2, + api_timeout=5, + type="HTTP", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + health_monitor = await response.parse() + assert_matches_type(TaskIDList, health_monitor, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.pools.health_monitors.with_streaming_response.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + delay=10, + max_retries=2, + api_timeout=5, + type="HTTP", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + health_monitor = await response.parse() + assert_matches_type(TaskIDList, health_monitor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + await async_client.cloud.load_balancers.pools.health_monitors.with_raw_response.create( + pool_id="", + project_id=1, + region_id=1, + delay=10, + max_retries=2, + api_timeout=5, + type="HTTP", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + health_monitor = await async_client.cloud.load_balancers.pools.health_monitors.delete( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert health_monitor is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.pools.health_monitors.with_raw_response.delete( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + health_monitor = await response.parse() + assert health_monitor is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.pools.health_monitors.with_streaming_response.delete( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + health_monitor = await response.parse() + assert health_monitor is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + await async_client.cloud.load_balancers.pools.health_monitors.with_raw_response.delete( + pool_id="", + project_id=1, + region_id=1, + ) diff --git a/tests/api_resources/cloud/load_balancers/pools/test_members.py b/tests/api_resources/cloud/load_balancers/pools/test_members.py new file mode 100644 index 00000000..57533ae8 --- /dev/null +++ b/tests/api_resources/cloud/load_balancers/pools/test_members.py @@ -0,0 +1,284 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import TaskIDList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMembers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + member = client.cloud.load_balancers.pools.members.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + address="192.168.40.33", + protocol_port=80, + ) + assert_matches_type(TaskIDList, member, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + member = client.cloud.load_balancers.pools.members.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + address="192.168.40.33", + protocol_port=80, + admin_state_up=True, + backup=True, + instance_id="a7e7e8d6-0bf7-4ac9-8170-831b47ee2ba9", + monitor_address="monitor_address", + monitor_port=1, + subnet_id="32283b0b-b560-4690-810c-f672cbb2e28d", + weight=1, + ) + assert_matches_type(TaskIDList, member, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.load_balancers.pools.members.with_raw_response.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + address="192.168.40.33", + protocol_port=80, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + member = response.parse() + assert_matches_type(TaskIDList, member, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.load_balancers.pools.members.with_streaming_response.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + address="192.168.40.33", + protocol_port=80, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + member = response.parse() + assert_matches_type(TaskIDList, member, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + client.cloud.load_balancers.pools.members.with_raw_response.create( + pool_id="", + project_id=1, + region_id=1, + address="192.168.40.33", + protocol_port=80, + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + member = client.cloud.load_balancers.pools.members.delete( + member_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + pool_id="00000000-0000-4000-8000-000000000000", + ) + assert_matches_type(TaskIDList, member, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.load_balancers.pools.members.with_raw_response.delete( + member_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + pool_id="00000000-0000-4000-8000-000000000000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + member = response.parse() + assert_matches_type(TaskIDList, member, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.load_balancers.pools.members.with_streaming_response.delete( + member_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + pool_id="00000000-0000-4000-8000-000000000000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + member = response.parse() + assert_matches_type(TaskIDList, member, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + client.cloud.load_balancers.pools.members.with_raw_response.delete( + member_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + pool_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `member_id` but received ''"): + client.cloud.load_balancers.pools.members.with_raw_response.delete( + member_id="", + project_id=1, + region_id=1, + pool_id="00000000-0000-4000-8000-000000000000", + ) + + +class TestAsyncMembers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + member = await async_client.cloud.load_balancers.pools.members.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + address="192.168.40.33", + protocol_port=80, + ) + assert_matches_type(TaskIDList, member, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + member = await async_client.cloud.load_balancers.pools.members.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + address="192.168.40.33", + protocol_port=80, + admin_state_up=True, + backup=True, + instance_id="a7e7e8d6-0bf7-4ac9-8170-831b47ee2ba9", + monitor_address="monitor_address", + monitor_port=1, + subnet_id="32283b0b-b560-4690-810c-f672cbb2e28d", + weight=1, + ) + assert_matches_type(TaskIDList, member, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.pools.members.with_raw_response.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + address="192.168.40.33", + protocol_port=80, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + member = await response.parse() + assert_matches_type(TaskIDList, member, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.pools.members.with_streaming_response.create( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + address="192.168.40.33", + protocol_port=80, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + member = await response.parse() + assert_matches_type(TaskIDList, member, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + await async_client.cloud.load_balancers.pools.members.with_raw_response.create( + pool_id="", + project_id=1, + region_id=1, + address="192.168.40.33", + protocol_port=80, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + member = await async_client.cloud.load_balancers.pools.members.delete( + member_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + pool_id="00000000-0000-4000-8000-000000000000", + ) + assert_matches_type(TaskIDList, member, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.pools.members.with_raw_response.delete( + member_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + pool_id="00000000-0000-4000-8000-000000000000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + member = await response.parse() + assert_matches_type(TaskIDList, member, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.pools.members.with_streaming_response.delete( + member_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + pool_id="00000000-0000-4000-8000-000000000000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + member = await response.parse() + assert_matches_type(TaskIDList, member, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + await async_client.cloud.load_balancers.pools.members.with_raw_response.delete( + member_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + pool_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `member_id` but received ''"): + await async_client.cloud.load_balancers.pools.members.with_raw_response.delete( + member_id="", + project_id=1, + region_id=1, + pool_id="00000000-0000-4000-8000-000000000000", + ) diff --git a/tests/api_resources/cloud/load_balancers/test_flavors.py b/tests/api_resources/cloud/load_balancers/test_flavors.py new file mode 100644 index 00000000..49f14df1 --- /dev/null +++ b/tests/api_resources/cloud/load_balancers/test_flavors.py @@ -0,0 +1,110 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import LoadBalancerFlavorList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFlavors: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + flavor = client.cloud.load_balancers.flavors.list( + project_id=1, + region_id=7, + ) + assert_matches_type(LoadBalancerFlavorList, flavor, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + flavor = client.cloud.load_balancers.flavors.list( + project_id=1, + region_id=7, + include_prices=True, + ) + assert_matches_type(LoadBalancerFlavorList, flavor, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.load_balancers.flavors.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = response.parse() + assert_matches_type(LoadBalancerFlavorList, flavor, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.load_balancers.flavors.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = response.parse() + assert_matches_type(LoadBalancerFlavorList, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncFlavors: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.load_balancers.flavors.list( + project_id=1, + region_id=7, + ) + assert_matches_type(LoadBalancerFlavorList, flavor, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + flavor = await async_client.cloud.load_balancers.flavors.list( + project_id=1, + region_id=7, + include_prices=True, + ) + assert_matches_type(LoadBalancerFlavorList, flavor, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.flavors.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flavor = await response.parse() + assert_matches_type(LoadBalancerFlavorList, flavor, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.flavors.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flavor = await response.parse() + assert_matches_type(LoadBalancerFlavorList, flavor, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/load_balancers/test_l7_policies.py b/tests/api_resources/cloud/load_balancers/test_l7_policies.py new file mode 100644 index 00000000..aae51218 --- /dev/null +++ b/tests/api_resources/cloud/load_balancers/test_l7_policies.py @@ -0,0 +1,1266 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import TaskIDList, LoadBalancerL7Policy, LoadBalancerL7PolicyList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestL7Policies: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create_overload_1(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_url="https://www.example.com", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_1(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_url="https://www.example.com", + name="redirect-example.com", + position=1, + redirect_http_code=301, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_raw_response_create_overload_1(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.with_raw_response.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_url="https://www.example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_1(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.with_streaming_response.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_url="https://www.example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_2(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_prefix="/api/v1/policies", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_2(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_prefix="/api/v1/policies", + name="redirect-example.com", + position=1, + redirect_http_code=301, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_raw_response_create_overload_2(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.with_raw_response.create( + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_prefix="/api/v1/policies", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_2(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.with_streaming_response.create( + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_prefix="/api/v1/policies", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_3(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_3(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + name="redirect-example.com", + position=1, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_raw_response_create_overload_3(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.with_raw_response.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_3(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.with_streaming_response.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_4(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REJECT", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_4(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REJECT", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + name="redirect-example.com", + position=1, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_raw_response_create_overload_4(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.with_raw_response.create( + project_id=1, + region_id=1, + action="REJECT", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_4(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.with_streaming_response.create( + project_id=1, + region_id=1, + action="REJECT", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update_overload_1(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + redirect_url="https://www.example.com", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_method_update_with_all_params_overload_1(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + redirect_url="https://www.example.com", + name="redirect-example.com", + position=1, + redirect_http_code=301, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_raw_response_update_overload_1(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + redirect_url="https://www.example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_streaming_response_update_overload_1(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.with_streaming_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + redirect_url="https://www.example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update_overload_1(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="", + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + redirect_url="https://www.example.com", + ) + + @parametrize + def test_method_update_overload_2(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + redirect_prefix="/api/v1/policies", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_method_update_with_all_params_overload_2(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + redirect_prefix="/api/v1/policies", + name="redirect-example.com", + position=1, + redirect_http_code=301, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_raw_response_update_overload_2(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + redirect_prefix="/api/v1/policies", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_streaming_response_update_overload_2(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.with_streaming_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + redirect_prefix="/api/v1/policies", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update_overload_2(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="", + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + redirect_prefix="/api/v1/policies", + ) + + @parametrize + def test_method_update_overload_3(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_method_update_with_all_params_overload_3(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + name="redirect-example.com", + position=1, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_raw_response_update_overload_3(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_streaming_response_update_overload_3(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.with_streaming_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update_overload_3(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="", + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) + + @parametrize + def test_method_update_overload_4(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REJECT", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_method_update_with_all_params_overload_4(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REJECT", + name="redirect-example.com", + position=1, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_raw_response_update_overload_4(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REJECT", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_streaming_response_update_overload_4(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.with_streaming_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REJECT", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update_overload_4(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="", + project_id=1, + region_id=1, + action="REJECT", + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.list( + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerL7PolicyList, l7_policy, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = response.parse() + assert_matches_type(LoadBalancerL7PolicyList, l7_policy, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = response.parse() + assert_matches_type(LoadBalancerL7PolicyList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.delete( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.with_raw_response.delete( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.with_streaming_response.delete( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + client.cloud.load_balancers.l7_policies.with_raw_response.delete( + l7policy_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + l7_policy = client.cloud.load_balancers.l7_policies.get( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerL7Policy, l7_policy, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.load_balancers.l7_policies.with_raw_response.get( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = response.parse() + assert_matches_type(LoadBalancerL7Policy, l7_policy, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.load_balancers.l7_policies.with_streaming_response.get( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = response.parse() + assert_matches_type(LoadBalancerL7Policy, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + client.cloud.load_balancers.l7_policies.with_raw_response.get( + l7policy_id="", + project_id=1, + region_id=1, + ) + + +class TestAsyncL7Policies: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create_overload_1(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_url="https://www.example.com", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_1(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_url="https://www.example.com", + name="redirect-example.com", + position=1, + redirect_http_code=301, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.with_raw_response.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_url="https://www.example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.with_streaming_response.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_url="https://www.example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_2(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_prefix="/api/v1/policies", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_2(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_prefix="/api/v1/policies", + name="redirect-example.com", + position=1, + redirect_http_code=301, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.with_raw_response.create( + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_prefix="/api/v1/policies", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.with_streaming_response.create( + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_prefix="/api/v1/policies", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_3(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_3(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + name="redirect-example.com", + position=1, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_3(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.with_raw_response.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_3(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.with_streaming_response.create( + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_4(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REJECT", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_4(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.create( + project_id=1, + region_id=1, + action="REJECT", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + name="redirect-example.com", + position=1, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_4(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.with_raw_response.create( + project_id=1, + region_id=1, + action="REJECT", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_4(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.with_streaming_response.create( + project_id=1, + region_id=1, + action="REJECT", + listener_id="023f2e34-7806-443b-bfae-16c324569a3d", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update_overload_1(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + redirect_url="https://www.example.com", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_method_update_with_all_params_overload_1(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + redirect_url="https://www.example.com", + name="redirect-example.com", + position=1, + redirect_http_code=301, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_raw_response_update_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + redirect_url="https://www.example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_streaming_response_update_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.with_streaming_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + redirect_url="https://www.example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update_overload_1(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="", + project_id=1, + region_id=1, + action="REDIRECT_TO_URL", + redirect_url="https://www.example.com", + ) + + @parametrize + async def test_method_update_overload_2(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + redirect_prefix="/api/v1/policies", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_method_update_with_all_params_overload_2(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + redirect_prefix="/api/v1/policies", + name="redirect-example.com", + position=1, + redirect_http_code=301, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_raw_response_update_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + redirect_prefix="/api/v1/policies", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_streaming_response_update_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.with_streaming_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + redirect_prefix="/api/v1/policies", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update_overload_2(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="", + project_id=1, + region_id=1, + action="REDIRECT_PREFIX", + redirect_prefix="/api/v1/policies", + ) + + @parametrize + async def test_method_update_overload_3(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_method_update_with_all_params_overload_3(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + name="redirect-example.com", + position=1, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_raw_response_update_overload_3(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_streaming_response_update_overload_3(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.with_streaming_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update_overload_3(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="", + project_id=1, + region_id=1, + action="REDIRECT_TO_POOL", + redirect_pool_id="00000000-0000-4000-8000-000000000000", + ) + + @parametrize + async def test_method_update_overload_4(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REJECT", + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_method_update_with_all_params_overload_4(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REJECT", + name="redirect-example.com", + position=1, + tags=["test_tag"], + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_raw_response_update_overload_4(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REJECT", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_streaming_response_update_overload_4(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.with_streaming_response.update( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + action="REJECT", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update_overload_4(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.with_raw_response.update( + l7policy_id="", + project_id=1, + region_id=1, + action="REJECT", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.list( + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerL7PolicyList, l7_policy, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = await response.parse() + assert_matches_type(LoadBalancerL7PolicyList, l7_policy, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = await response.parse() + assert_matches_type(LoadBalancerL7PolicyList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.delete( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.with_raw_response.delete( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.with_streaming_response.delete( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = await response.parse() + assert_matches_type(TaskIDList, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.with_raw_response.delete( + l7policy_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + l7_policy = await async_client.cloud.load_balancers.l7_policies.get( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerL7Policy, l7_policy, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.l7_policies.with_raw_response.get( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + l7_policy = await response.parse() + assert_matches_type(LoadBalancerL7Policy, l7_policy, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.l7_policies.with_streaming_response.get( + l7policy_id="023f2e34-7806-443b-bfae-16c324569a3d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + l7_policy = await response.parse() + assert_matches_type(LoadBalancerL7Policy, l7_policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `l7policy_id` but received ''"): + await async_client.cloud.load_balancers.l7_policies.with_raw_response.get( + l7policy_id="", + project_id=1, + region_id=1, + ) diff --git a/tests/api_resources/cloud/load_balancers/test_listeners.py b/tests/api_resources/cloud/load_balancers/test_listeners.py new file mode 100644 index 00000000..81c7a2b2 --- /dev/null +++ b/tests/api_resources/cloud/load_balancers/test_listeners.py @@ -0,0 +1,622 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import TaskIDList, LoadBalancerListenerList, LoadBalancerListenerDetail + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestListeners: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + listener = client.cloud.load_balancers.listeners.create( + project_id=1, + region_id=1, + load_balancer_id="30f4f55b-4a7c-48e0-9954-5cddfee216e7", + name="my_listener", + protocol="HTTP", + protocol_port=80, + ) + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + listener = client.cloud.load_balancers.listeners.create( + project_id=1, + region_id=1, + load_balancer_id="30f4f55b-4a7c-48e0-9954-5cddfee216e7", + name="my_listener", + protocol="HTTP", + protocol_port=80, + allowed_cidrs=["10.0.0.0/8"], + connection_limit=100000, + default_pool_id="00000000-0000-4000-8000-000000000000", + insert_x_forwarded=False, + secret_id="", + sni_secret_id=["f2e734d0-fa2b-42c2-ad33-4c6db5101e00", "eb121225-7ded-4ff3-ae1f-599e145dd7cb"], + timeout_client_data=50000, + timeout_member_connect=50000, + timeout_member_data=None, + user_list=[ + { + "encrypted_password": "$5$isRr.HJ1IrQP38.m$oViu3DJOpUG2ZsjCBtbITV3mqpxxbZfyWJojLPNSPO5", + "username": "admin", + } + ], + ) + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.load_balancers.listeners.with_raw_response.create( + project_id=1, + region_id=1, + load_balancer_id="30f4f55b-4a7c-48e0-9954-5cddfee216e7", + name="my_listener", + protocol="HTTP", + protocol_port=80, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + listener = response.parse() + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.load_balancers.listeners.with_streaming_response.create( + project_id=1, + region_id=1, + load_balancer_id="30f4f55b-4a7c-48e0-9954-5cddfee216e7", + name="my_listener", + protocol="HTTP", + protocol_port=80, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + listener = response.parse() + assert_matches_type(TaskIDList, listener, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + listener = client.cloud.load_balancers.listeners.update( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + listener = client.cloud.load_balancers.listeners.update( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + admin_state_up=True, + allowed_cidrs=["10.0.0.0/8"], + connection_limit=100000, + name="new_listener_name", + secret_id="af4a64e7-03ca-470f-9a09-b77d54c5abd8", + sni_secret_id=["af4a64e7-03ca-470f-9a09-b77d54c5abd8", "12b43d95-d420-4c79-a883-49bf146cbdff"], + timeout_client_data=50000, + timeout_member_connect=50000, + timeout_member_data=None, + user_list=[ + { + "encrypted_password": "$5$isRr.HJ1IrQP38.m$oViu3DJOpUG2ZsjCBtbITV3mqpxxbZfyWJojLPNSPO5", + "username": "admin", + } + ], + ) + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.load_balancers.listeners.with_raw_response.update( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + listener = response.parse() + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.load_balancers.listeners.with_streaming_response.update( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + listener = response.parse() + assert_matches_type(TaskIDList, listener, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `listener_id` but received ''"): + client.cloud.load_balancers.listeners.with_raw_response.update( + listener_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + listener = client.cloud.load_balancers.listeners.list( + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerListenerList, listener, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + listener = client.cloud.load_balancers.listeners.list( + project_id=1, + region_id=1, + load_balancer_id="00000000-0000-4000-8000-000000000000", + show_stats=True, + ) + assert_matches_type(LoadBalancerListenerList, listener, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.load_balancers.listeners.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + listener = response.parse() + assert_matches_type(LoadBalancerListenerList, listener, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.load_balancers.listeners.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + listener = response.parse() + assert_matches_type(LoadBalancerListenerList, listener, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + listener = client.cloud.load_balancers.listeners.delete( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + def test_method_delete_with_all_params(self, client: Gcore) -> None: + listener = client.cloud.load_balancers.listeners.delete( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + delete_default_pool=False, + ) + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.load_balancers.listeners.with_raw_response.delete( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + listener = response.parse() + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.load_balancers.listeners.with_streaming_response.delete( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + listener = response.parse() + assert_matches_type(TaskIDList, listener, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `listener_id` but received ''"): + client.cloud.load_balancers.listeners.with_raw_response.delete( + listener_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + listener = client.cloud.load_balancers.listeners.get( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerListenerDetail, listener, path=["response"]) + + @parametrize + def test_method_get_with_all_params(self, client: Gcore) -> None: + listener = client.cloud.load_balancers.listeners.get( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + show_stats=True, + ) + assert_matches_type(LoadBalancerListenerDetail, listener, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.load_balancers.listeners.with_raw_response.get( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + listener = response.parse() + assert_matches_type(LoadBalancerListenerDetail, listener, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.load_balancers.listeners.with_streaming_response.get( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + listener = response.parse() + assert_matches_type(LoadBalancerListenerDetail, listener, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `listener_id` but received ''"): + client.cloud.load_balancers.listeners.with_raw_response.get( + listener_id="", + project_id=1, + region_id=1, + ) + + +class TestAsyncListeners: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + listener = await async_client.cloud.load_balancers.listeners.create( + project_id=1, + region_id=1, + load_balancer_id="30f4f55b-4a7c-48e0-9954-5cddfee216e7", + name="my_listener", + protocol="HTTP", + protocol_port=80, + ) + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + listener = await async_client.cloud.load_balancers.listeners.create( + project_id=1, + region_id=1, + load_balancer_id="30f4f55b-4a7c-48e0-9954-5cddfee216e7", + name="my_listener", + protocol="HTTP", + protocol_port=80, + allowed_cidrs=["10.0.0.0/8"], + connection_limit=100000, + default_pool_id="00000000-0000-4000-8000-000000000000", + insert_x_forwarded=False, + secret_id="", + sni_secret_id=["f2e734d0-fa2b-42c2-ad33-4c6db5101e00", "eb121225-7ded-4ff3-ae1f-599e145dd7cb"], + timeout_client_data=50000, + timeout_member_connect=50000, + timeout_member_data=None, + user_list=[ + { + "encrypted_password": "$5$isRr.HJ1IrQP38.m$oViu3DJOpUG2ZsjCBtbITV3mqpxxbZfyWJojLPNSPO5", + "username": "admin", + } + ], + ) + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.listeners.with_raw_response.create( + project_id=1, + region_id=1, + load_balancer_id="30f4f55b-4a7c-48e0-9954-5cddfee216e7", + name="my_listener", + protocol="HTTP", + protocol_port=80, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + listener = await response.parse() + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.listeners.with_streaming_response.create( + project_id=1, + region_id=1, + load_balancer_id="30f4f55b-4a7c-48e0-9954-5cddfee216e7", + name="my_listener", + protocol="HTTP", + protocol_port=80, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + listener = await response.parse() + assert_matches_type(TaskIDList, listener, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + listener = await async_client.cloud.load_balancers.listeners.update( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + listener = await async_client.cloud.load_balancers.listeners.update( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + admin_state_up=True, + allowed_cidrs=["10.0.0.0/8"], + connection_limit=100000, + name="new_listener_name", + secret_id="af4a64e7-03ca-470f-9a09-b77d54c5abd8", + sni_secret_id=["af4a64e7-03ca-470f-9a09-b77d54c5abd8", "12b43d95-d420-4c79-a883-49bf146cbdff"], + timeout_client_data=50000, + timeout_member_connect=50000, + timeout_member_data=None, + user_list=[ + { + "encrypted_password": "$5$isRr.HJ1IrQP38.m$oViu3DJOpUG2ZsjCBtbITV3mqpxxbZfyWJojLPNSPO5", + "username": "admin", + } + ], + ) + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.listeners.with_raw_response.update( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + listener = await response.parse() + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.listeners.with_streaming_response.update( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + listener = await response.parse() + assert_matches_type(TaskIDList, listener, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `listener_id` but received ''"): + await async_client.cloud.load_balancers.listeners.with_raw_response.update( + listener_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + listener = await async_client.cloud.load_balancers.listeners.list( + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerListenerList, listener, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + listener = await async_client.cloud.load_balancers.listeners.list( + project_id=1, + region_id=1, + load_balancer_id="00000000-0000-4000-8000-000000000000", + show_stats=True, + ) + assert_matches_type(LoadBalancerListenerList, listener, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.listeners.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + listener = await response.parse() + assert_matches_type(LoadBalancerListenerList, listener, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.listeners.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + listener = await response.parse() + assert_matches_type(LoadBalancerListenerList, listener, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + listener = await async_client.cloud.load_balancers.listeners.delete( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGcore) -> None: + listener = await async_client.cloud.load_balancers.listeners.delete( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + delete_default_pool=False, + ) + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.listeners.with_raw_response.delete( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + listener = await response.parse() + assert_matches_type(TaskIDList, listener, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.listeners.with_streaming_response.delete( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + listener = await response.parse() + assert_matches_type(TaskIDList, listener, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `listener_id` but received ''"): + await async_client.cloud.load_balancers.listeners.with_raw_response.delete( + listener_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + listener = await async_client.cloud.load_balancers.listeners.get( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerListenerDetail, listener, path=["response"]) + + @parametrize + async def test_method_get_with_all_params(self, async_client: AsyncGcore) -> None: + listener = await async_client.cloud.load_balancers.listeners.get( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + show_stats=True, + ) + assert_matches_type(LoadBalancerListenerDetail, listener, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.listeners.with_raw_response.get( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + listener = await response.parse() + assert_matches_type(LoadBalancerListenerDetail, listener, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.listeners.with_streaming_response.get( + listener_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + listener = await response.parse() + assert_matches_type(LoadBalancerListenerDetail, listener, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `listener_id` but received ''"): + await async_client.cloud.load_balancers.listeners.with_raw_response.get( + listener_id="", + project_id=1, + region_id=1, + ) diff --git a/tests/api_resources/cloud/load_balancers/test_metrics.py b/tests/api_resources/cloud/load_balancers/test_metrics.py new file mode 100644 index 00000000..3ab21ffd --- /dev/null +++ b/tests/api_resources/cloud/load_balancers/test_metrics.py @@ -0,0 +1,132 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import LoadBalancerMetricsList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMetrics: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + metric = client.cloud.load_balancers.metrics.list( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + time_interval=6, + time_unit="day", + ) + assert_matches_type(LoadBalancerMetricsList, metric, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.load_balancers.metrics.with_raw_response.list( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + time_interval=6, + time_unit="day", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + metric = response.parse() + assert_matches_type(LoadBalancerMetricsList, metric, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.load_balancers.metrics.with_streaming_response.list( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + time_interval=6, + time_unit="day", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + metric = response.parse() + assert_matches_type(LoadBalancerMetricsList, metric, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + client.cloud.load_balancers.metrics.with_raw_response.list( + load_balancer_id="", + project_id=1, + region_id=7, + time_interval=6, + time_unit="day", + ) + + +class TestAsyncMetrics: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + metric = await async_client.cloud.load_balancers.metrics.list( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + time_interval=6, + time_unit="day", + ) + assert_matches_type(LoadBalancerMetricsList, metric, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.metrics.with_raw_response.list( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + time_interval=6, + time_unit="day", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + metric = await response.parse() + assert_matches_type(LoadBalancerMetricsList, metric, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.metrics.with_streaming_response.list( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + time_interval=6, + time_unit="day", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + metric = await response.parse() + assert_matches_type(LoadBalancerMetricsList, metric, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + await async_client.cloud.load_balancers.metrics.with_raw_response.list( + load_balancer_id="", + project_id=1, + region_id=7, + time_interval=6, + time_unit="day", + ) diff --git a/tests/api_resources/cloud/load_balancers/test_pools.py b/tests/api_resources/cloud/load_balancers/test_pools.py new file mode 100644 index 00000000..7039089f --- /dev/null +++ b/tests/api_resources/cloud/load_balancers/test_pools.py @@ -0,0 +1,694 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import TaskIDList, LoadBalancerPool, LoadBalancerPoolList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPools: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + pool = client.cloud.load_balancers.pools.create( + project_id=1, + region_id=1, + lb_algorithm="LEAST_CONNECTIONS", + name="pool_name", + protocol="HTTP", + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + pool = client.cloud.load_balancers.pools.create( + project_id=1, + region_id=1, + lb_algorithm="LEAST_CONNECTIONS", + name="pool_name", + protocol="HTTP", + ca_secret_id="ca_secret_id", + crl_secret_id="crl_secret_id", + healthmonitor={ + "delay": 10, + "max_retries": 3, + "timeout": 5, + "type": "HTTP", + "admin_state_up": True, + "expected_codes": "200,301,302", + "http_method": "GET", + "max_retries_down": 3, + "url_path": "/", + }, + listener_id="listener_id", + load_balancer_id="bbb35f84-35cc-4b2f-84c2-a6a29bba68aa", + members=[ + { + "address": "192.168.1.101", + "protocol_port": 8000, + "admin_state_up": True, + "backup": True, + "instance_id": "a7e7e8d6-0bf7-4ac9-8170-831b47ee2ba9", + "monitor_address": "monitor_address", + "monitor_port": 1, + "subnet_id": "32283b0b-b560-4690-810c-f672cbb2e28d", + "weight": 2, + }, + { + "address": "192.168.1.102", + "protocol_port": 8000, + "admin_state_up": True, + "backup": True, + "instance_id": "169942e0-9b53-42df-95ef-1a8b6525c2bd", + "monitor_address": "monitor_address", + "monitor_port": 1, + "subnet_id": "32283b0b-b560-4690-810c-f672cbb2e28d", + "weight": 4, + }, + ], + secret_id="secret_id", + session_persistence={ + "type": "APP_COOKIE", + "cookie_name": "cookie_name", + "persistence_granularity": "persistence_granularity", + "persistence_timeout": 0, + }, + timeout_client_data=50000, + timeout_member_connect=50000, + timeout_member_data=0, + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.load_balancers.pools.with_raw_response.create( + project_id=1, + region_id=1, + lb_algorithm="LEAST_CONNECTIONS", + name="pool_name", + protocol="HTTP", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.load_balancers.pools.with_streaming_response.create( + project_id=1, + region_id=1, + lb_algorithm="LEAST_CONNECTIONS", + name="pool_name", + protocol="HTTP", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + pool = client.cloud.load_balancers.pools.update( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + pool = client.cloud.load_balancers.pools.update( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + admin_state_up=True, + ca_secret_id="ca_secret_id", + crl_secret_id="crl_secret_id", + healthmonitor={ + "delay": 10, + "max_retries": 2, + "timeout": 5, + "admin_state_up": True, + "expected_codes": "200,301,302", + "http_method": "CONNECT", + "max_retries_down": 2, + "type": "HTTP", + "url_path": "/", + }, + lb_algorithm="LEAST_CONNECTIONS", + members=[ + { + "address": "192.168.40.33", + "protocol_port": 80, + "admin_state_up": True, + "backup": True, + "instance_id": "a7e7e8d6-0bf7-4ac9-8170-831b47ee2ba9", + "monitor_address": "monitor_address", + "monitor_port": 1, + "subnet_id": "32283b0b-b560-4690-810c-f672cbb2e28d", + "weight": 1, + } + ], + name="new_pool_name", + protocol="HTTP", + secret_id="secret_id", + session_persistence={ + "type": "APP_COOKIE", + "cookie_name": "cookie_name", + "persistence_granularity": "persistence_granularity", + "persistence_timeout": 0, + }, + timeout_client_data=50000, + timeout_member_connect=50000, + timeout_member_data=0, + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.load_balancers.pools.with_raw_response.update( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.load_balancers.pools.with_streaming_response.update( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + client.cloud.load_balancers.pools.with_raw_response.update( + pool_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + pool = client.cloud.load_balancers.pools.list( + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerPoolList, pool, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + pool = client.cloud.load_balancers.pools.list( + project_id=1, + region_id=1, + details=True, + listener_id="00000000-0000-4000-8000-000000000000", + load_balancer_id="00000000-0000-4000-8000-000000000000", + ) + assert_matches_type(LoadBalancerPoolList, pool, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.load_balancers.pools.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = response.parse() + assert_matches_type(LoadBalancerPoolList, pool, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.load_balancers.pools.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = response.parse() + assert_matches_type(LoadBalancerPoolList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + pool = client.cloud.load_balancers.pools.delete( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.load_balancers.pools.with_raw_response.delete( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.load_balancers.pools.with_streaming_response.delete( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + client.cloud.load_balancers.pools.with_raw_response.delete( + pool_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + pool = client.cloud.load_balancers.pools.get( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerPool, pool, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.load_balancers.pools.with_raw_response.get( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = response.parse() + assert_matches_type(LoadBalancerPool, pool, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.load_balancers.pools.with_streaming_response.get( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = response.parse() + assert_matches_type(LoadBalancerPool, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + client.cloud.load_balancers.pools.with_raw_response.get( + pool_id="", + project_id=1, + region_id=1, + ) + + +class TestAsyncPools: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.load_balancers.pools.create( + project_id=1, + region_id=1, + lb_algorithm="LEAST_CONNECTIONS", + name="pool_name", + protocol="HTTP", + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.load_balancers.pools.create( + project_id=1, + region_id=1, + lb_algorithm="LEAST_CONNECTIONS", + name="pool_name", + protocol="HTTP", + ca_secret_id="ca_secret_id", + crl_secret_id="crl_secret_id", + healthmonitor={ + "delay": 10, + "max_retries": 3, + "timeout": 5, + "type": "HTTP", + "admin_state_up": True, + "expected_codes": "200,301,302", + "http_method": "GET", + "max_retries_down": 3, + "url_path": "/", + }, + listener_id="listener_id", + load_balancer_id="bbb35f84-35cc-4b2f-84c2-a6a29bba68aa", + members=[ + { + "address": "192.168.1.101", + "protocol_port": 8000, + "admin_state_up": True, + "backup": True, + "instance_id": "a7e7e8d6-0bf7-4ac9-8170-831b47ee2ba9", + "monitor_address": "monitor_address", + "monitor_port": 1, + "subnet_id": "32283b0b-b560-4690-810c-f672cbb2e28d", + "weight": 2, + }, + { + "address": "192.168.1.102", + "protocol_port": 8000, + "admin_state_up": True, + "backup": True, + "instance_id": "169942e0-9b53-42df-95ef-1a8b6525c2bd", + "monitor_address": "monitor_address", + "monitor_port": 1, + "subnet_id": "32283b0b-b560-4690-810c-f672cbb2e28d", + "weight": 4, + }, + ], + secret_id="secret_id", + session_persistence={ + "type": "APP_COOKIE", + "cookie_name": "cookie_name", + "persistence_granularity": "persistence_granularity", + "persistence_timeout": 0, + }, + timeout_client_data=50000, + timeout_member_connect=50000, + timeout_member_data=0, + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.pools.with_raw_response.create( + project_id=1, + region_id=1, + lb_algorithm="LEAST_CONNECTIONS", + name="pool_name", + protocol="HTTP", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = await response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.pools.with_streaming_response.create( + project_id=1, + region_id=1, + lb_algorithm="LEAST_CONNECTIONS", + name="pool_name", + protocol="HTTP", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = await response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.load_balancers.pools.update( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.load_balancers.pools.update( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + admin_state_up=True, + ca_secret_id="ca_secret_id", + crl_secret_id="crl_secret_id", + healthmonitor={ + "delay": 10, + "max_retries": 2, + "timeout": 5, + "admin_state_up": True, + "expected_codes": "200,301,302", + "http_method": "CONNECT", + "max_retries_down": 2, + "type": "HTTP", + "url_path": "/", + }, + lb_algorithm="LEAST_CONNECTIONS", + members=[ + { + "address": "192.168.40.33", + "protocol_port": 80, + "admin_state_up": True, + "backup": True, + "instance_id": "a7e7e8d6-0bf7-4ac9-8170-831b47ee2ba9", + "monitor_address": "monitor_address", + "monitor_port": 1, + "subnet_id": "32283b0b-b560-4690-810c-f672cbb2e28d", + "weight": 1, + } + ], + name="new_pool_name", + protocol="HTTP", + secret_id="secret_id", + session_persistence={ + "type": "APP_COOKIE", + "cookie_name": "cookie_name", + "persistence_granularity": "persistence_granularity", + "persistence_timeout": 0, + }, + timeout_client_data=50000, + timeout_member_connect=50000, + timeout_member_data=0, + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.pools.with_raw_response.update( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = await response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.pools.with_streaming_response.update( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = await response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + await async_client.cloud.load_balancers.pools.with_raw_response.update( + pool_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.load_balancers.pools.list( + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerPoolList, pool, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.load_balancers.pools.list( + project_id=1, + region_id=1, + details=True, + listener_id="00000000-0000-4000-8000-000000000000", + load_balancer_id="00000000-0000-4000-8000-000000000000", + ) + assert_matches_type(LoadBalancerPoolList, pool, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.pools.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = await response.parse() + assert_matches_type(LoadBalancerPoolList, pool, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.pools.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = await response.parse() + assert_matches_type(LoadBalancerPoolList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.load_balancers.pools.delete( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.pools.with_raw_response.delete( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = await response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.pools.with_streaming_response.delete( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = await response.parse() + assert_matches_type(TaskIDList, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + await async_client.cloud.load_balancers.pools.with_raw_response.delete( + pool_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.load_balancers.pools.get( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(LoadBalancerPool, pool, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.pools.with_raw_response.get( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + pool = await response.parse() + assert_matches_type(LoadBalancerPool, pool, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.pools.with_streaming_response.get( + pool_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + pool = await response.parse() + assert_matches_type(LoadBalancerPool, pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pool_id` but received ''"): + await async_client.cloud.load_balancers.pools.with_raw_response.get( + pool_id="", + project_id=1, + region_id=1, + ) diff --git a/tests/api_resources/cloud/load_balancers/test_statuses.py b/tests/api_resources/cloud/load_balancers/test_statuses.py new file mode 100644 index 00000000..9de4628c --- /dev/null +++ b/tests/api_resources/cloud/load_balancers/test_statuses.py @@ -0,0 +1,184 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import LoadBalancerStatus, LoadBalancerStatusList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestStatuses: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + status = client.cloud.load_balancers.statuses.list( + project_id=1, + region_id=7, + ) + assert_matches_type(LoadBalancerStatusList, status, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.load_balancers.statuses.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + status = response.parse() + assert_matches_type(LoadBalancerStatusList, status, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.load_balancers.statuses.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + status = response.parse() + assert_matches_type(LoadBalancerStatusList, status, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + status = client.cloud.load_balancers.statuses.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + assert_matches_type(LoadBalancerStatus, status, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.load_balancers.statuses.with_raw_response.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + status = response.parse() + assert_matches_type(LoadBalancerStatus, status, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.load_balancers.statuses.with_streaming_response.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + status = response.parse() + assert_matches_type(LoadBalancerStatus, status, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + client.cloud.load_balancers.statuses.with_raw_response.get( + load_balancer_id="", + project_id=1, + region_id=7, + ) + + +class TestAsyncStatuses: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + status = await async_client.cloud.load_balancers.statuses.list( + project_id=1, + region_id=7, + ) + assert_matches_type(LoadBalancerStatusList, status, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.statuses.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + status = await response.parse() + assert_matches_type(LoadBalancerStatusList, status, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.statuses.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + status = await response.parse() + assert_matches_type(LoadBalancerStatusList, status, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + status = await async_client.cloud.load_balancers.statuses.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + assert_matches_type(LoadBalancerStatus, status, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.statuses.with_raw_response.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + status = await response.parse() + assert_matches_type(LoadBalancerStatus, status, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.statuses.with_streaming_response.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + status = await response.parse() + assert_matches_type(LoadBalancerStatus, status, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + await async_client.cloud.load_balancers.statuses.with_raw_response.get( + load_balancer_id="", + project_id=1, + region_id=7, + ) diff --git a/tests/api_resources/cloud/networks/__init__.py b/tests/api_resources/cloud/networks/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/networks/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/networks/test_routers.py b/tests/api_resources/cloud/networks/test_routers.py new file mode 100644 index 00000000..968607af --- /dev/null +++ b/tests/api_resources/cloud/networks/test_routers.py @@ -0,0 +1,796 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import TaskIDList +from gcore.types.cloud.networks import ( + Router, +) + +# pyright: reportDeprecated=false + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRouters: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + router = client.cloud.networks.routers.create( + project_id=0, + region_id=0, + name="my_wonderful_router", + ) + assert_matches_type(TaskIDList, router, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + router = client.cloud.networks.routers.create( + project_id=0, + region_id=0, + name="my_wonderful_router", + external_gateway_info={ + "enable_snat": True, + "type": "default", + }, + interfaces=[ + { + "subnet_id": "3ed9e2ce-f906-47fb-ba32-c25a3f63df4f", + "type": "subnet", + } + ], + routes=[ + { + "destination": "10.0.3.0/24", + "nexthop": "10.0.0.13", + } + ], + ) + assert_matches_type(TaskIDList, router, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.networks.routers.with_raw_response.create( + project_id=0, + region_id=0, + name="my_wonderful_router", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = response.parse() + assert_matches_type(TaskIDList, router, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.networks.routers.with_streaming_response.create( + project_id=0, + region_id=0, + name="my_wonderful_router", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = response.parse() + assert_matches_type(TaskIDList, router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + router = client.cloud.networks.routers.update( + router_id="router_id", + project_id=0, + region_id=0, + ) + + assert_matches_type(Router, router, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + router = client.cloud.networks.routers.update( + router_id="router_id", + project_id=0, + region_id=0, + external_gateway_info={ + "network_id": "d7745dcf-b302-4795-9d61-6cc52487af48", + "enable_snat": False, + "type": "manual", + }, + name="my_renamed_router", + routes=[ + { + "destination": "10.0.3.0/24", + "nexthop": "10.0.0.13", + } + ], + ) + + assert_matches_type(Router, router, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + response = client.cloud.networks.routers.with_raw_response.update( + router_id="router_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = response.parse() + assert_matches_type(Router, router, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with client.cloud.networks.routers.with_streaming_response.update( + router_id="router_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = response.parse() + assert_matches_type(Router, router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `router_id` but received ''"): + client.cloud.networks.routers.with_raw_response.update( + router_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + router = client.cloud.networks.routers.list( + project_id=0, + region_id=0, + ) + assert_matches_type(SyncOffsetPage[Router], router, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + router = client.cloud.networks.routers.list( + project_id=0, + region_id=0, + limit=0, + offset=0, + ) + assert_matches_type(SyncOffsetPage[Router], router, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.networks.routers.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = response.parse() + assert_matches_type(SyncOffsetPage[Router], router, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.networks.routers.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = response.parse() + assert_matches_type(SyncOffsetPage[Router], router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + router = client.cloud.networks.routers.delete( + router_id="router_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, router, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.networks.routers.with_raw_response.delete( + router_id="router_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = response.parse() + assert_matches_type(TaskIDList, router, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.networks.routers.with_streaming_response.delete( + router_id="router_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = response.parse() + assert_matches_type(TaskIDList, router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `router_id` but received ''"): + client.cloud.networks.routers.with_raw_response.delete( + router_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_attach_subnet(self, client: Gcore) -> None: + router = client.cloud.networks.routers.attach_subnet( + router_id="ccd5b925-e35c-4611-a511-67ab503104c8", + project_id=1, + region_id=1, + subnet_id="subnet_id", + ) + assert_matches_type(Router, router, path=["response"]) + + @parametrize + def test_method_attach_subnet_with_all_params(self, client: Gcore) -> None: + router = client.cloud.networks.routers.attach_subnet( + router_id="ccd5b925-e35c-4611-a511-67ab503104c8", + project_id=1, + region_id=1, + subnet_id="subnet_id", + ip_address="ip_address", + ) + assert_matches_type(Router, router, path=["response"]) + + @parametrize + def test_raw_response_attach_subnet(self, client: Gcore) -> None: + response = client.cloud.networks.routers.with_raw_response.attach_subnet( + router_id="ccd5b925-e35c-4611-a511-67ab503104c8", + project_id=1, + region_id=1, + subnet_id="subnet_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = response.parse() + assert_matches_type(Router, router, path=["response"]) + + @parametrize + def test_streaming_response_attach_subnet(self, client: Gcore) -> None: + with client.cloud.networks.routers.with_streaming_response.attach_subnet( + router_id="ccd5b925-e35c-4611-a511-67ab503104c8", + project_id=1, + region_id=1, + subnet_id="subnet_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = response.parse() + assert_matches_type(Router, router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_attach_subnet(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `router_id` but received ''"): + client.cloud.networks.routers.with_raw_response.attach_subnet( + router_id="", + project_id=1, + region_id=1, + subnet_id="subnet_id", + ) + + @parametrize + def test_method_detach_subnet(self, client: Gcore) -> None: + router = client.cloud.networks.routers.detach_subnet( + router_id="router_id", + project_id=0, + region_id=0, + subnet_id="subnet_id", + ) + assert_matches_type(Router, router, path=["response"]) + + @parametrize + def test_raw_response_detach_subnet(self, client: Gcore) -> None: + response = client.cloud.networks.routers.with_raw_response.detach_subnet( + router_id="router_id", + project_id=0, + region_id=0, + subnet_id="subnet_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = response.parse() + assert_matches_type(Router, router, path=["response"]) + + @parametrize + def test_streaming_response_detach_subnet(self, client: Gcore) -> None: + with client.cloud.networks.routers.with_streaming_response.detach_subnet( + router_id="router_id", + project_id=0, + region_id=0, + subnet_id="subnet_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = response.parse() + assert_matches_type(Router, router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_detach_subnet(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `router_id` but received ''"): + client.cloud.networks.routers.with_raw_response.detach_subnet( + router_id="", + project_id=0, + region_id=0, + subnet_id="subnet_id", + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + router = client.cloud.networks.routers.get( + router_id="router_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Router, router, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.networks.routers.with_raw_response.get( + router_id="router_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = response.parse() + assert_matches_type(Router, router, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.networks.routers.with_streaming_response.get( + router_id="router_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = response.parse() + assert_matches_type(Router, router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `router_id` but received ''"): + client.cloud.networks.routers.with_raw_response.get( + router_id="", + project_id=0, + region_id=0, + ) + + +class TestAsyncRouters: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + router = await async_client.cloud.networks.routers.create( + project_id=0, + region_id=0, + name="my_wonderful_router", + ) + assert_matches_type(TaskIDList, router, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + router = await async_client.cloud.networks.routers.create( + project_id=0, + region_id=0, + name="my_wonderful_router", + external_gateway_info={ + "enable_snat": True, + "type": "default", + }, + interfaces=[ + { + "subnet_id": "3ed9e2ce-f906-47fb-ba32-c25a3f63df4f", + "type": "subnet", + } + ], + routes=[ + { + "destination": "10.0.3.0/24", + "nexthop": "10.0.0.13", + } + ], + ) + assert_matches_type(TaskIDList, router, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.routers.with_raw_response.create( + project_id=0, + region_id=0, + name="my_wonderful_router", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = await response.parse() + assert_matches_type(TaskIDList, router, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.routers.with_streaming_response.create( + project_id=0, + region_id=0, + name="my_wonderful_router", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = await response.parse() + assert_matches_type(TaskIDList, router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + router = await async_client.cloud.networks.routers.update( + router_id="router_id", + project_id=0, + region_id=0, + ) + + assert_matches_type(Router, router, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + router = await async_client.cloud.networks.routers.update( + router_id="router_id", + project_id=0, + region_id=0, + external_gateway_info={ + "network_id": "d7745dcf-b302-4795-9d61-6cc52487af48", + "enable_snat": False, + "type": "manual", + }, + name="my_renamed_router", + routes=[ + { + "destination": "10.0.3.0/24", + "nexthop": "10.0.0.13", + } + ], + ) + + assert_matches_type(Router, router, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + response = await async_client.cloud.networks.routers.with_raw_response.update( + router_id="router_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = await response.parse() + assert_matches_type(Router, router, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + async with async_client.cloud.networks.routers.with_streaming_response.update( + router_id="router_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = await response.parse() + assert_matches_type(Router, router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `router_id` but received ''"): + await async_client.cloud.networks.routers.with_raw_response.update( + router_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + router = await async_client.cloud.networks.routers.list( + project_id=0, + region_id=0, + ) + assert_matches_type(AsyncOffsetPage[Router], router, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + router = await async_client.cloud.networks.routers.list( + project_id=0, + region_id=0, + limit=0, + offset=0, + ) + assert_matches_type(AsyncOffsetPage[Router], router, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.routers.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = await response.parse() + assert_matches_type(AsyncOffsetPage[Router], router, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.routers.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = await response.parse() + assert_matches_type(AsyncOffsetPage[Router], router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + router = await async_client.cloud.networks.routers.delete( + router_id="router_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, router, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.routers.with_raw_response.delete( + router_id="router_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = await response.parse() + assert_matches_type(TaskIDList, router, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.routers.with_streaming_response.delete( + router_id="router_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = await response.parse() + assert_matches_type(TaskIDList, router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `router_id` but received ''"): + await async_client.cloud.networks.routers.with_raw_response.delete( + router_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_attach_subnet(self, async_client: AsyncGcore) -> None: + router = await async_client.cloud.networks.routers.attach_subnet( + router_id="ccd5b925-e35c-4611-a511-67ab503104c8", + project_id=1, + region_id=1, + subnet_id="subnet_id", + ) + assert_matches_type(Router, router, path=["response"]) + + @parametrize + async def test_method_attach_subnet_with_all_params(self, async_client: AsyncGcore) -> None: + router = await async_client.cloud.networks.routers.attach_subnet( + router_id="ccd5b925-e35c-4611-a511-67ab503104c8", + project_id=1, + region_id=1, + subnet_id="subnet_id", + ip_address="ip_address", + ) + assert_matches_type(Router, router, path=["response"]) + + @parametrize + async def test_raw_response_attach_subnet(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.routers.with_raw_response.attach_subnet( + router_id="ccd5b925-e35c-4611-a511-67ab503104c8", + project_id=1, + region_id=1, + subnet_id="subnet_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = await response.parse() + assert_matches_type(Router, router, path=["response"]) + + @parametrize + async def test_streaming_response_attach_subnet(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.routers.with_streaming_response.attach_subnet( + router_id="ccd5b925-e35c-4611-a511-67ab503104c8", + project_id=1, + region_id=1, + subnet_id="subnet_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = await response.parse() + assert_matches_type(Router, router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_attach_subnet(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `router_id` but received ''"): + await async_client.cloud.networks.routers.with_raw_response.attach_subnet( + router_id="", + project_id=1, + region_id=1, + subnet_id="subnet_id", + ) + + @parametrize + async def test_method_detach_subnet(self, async_client: AsyncGcore) -> None: + router = await async_client.cloud.networks.routers.detach_subnet( + router_id="router_id", + project_id=0, + region_id=0, + subnet_id="subnet_id", + ) + assert_matches_type(Router, router, path=["response"]) + + @parametrize + async def test_raw_response_detach_subnet(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.routers.with_raw_response.detach_subnet( + router_id="router_id", + project_id=0, + region_id=0, + subnet_id="subnet_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = await response.parse() + assert_matches_type(Router, router, path=["response"]) + + @parametrize + async def test_streaming_response_detach_subnet(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.routers.with_streaming_response.detach_subnet( + router_id="router_id", + project_id=0, + region_id=0, + subnet_id="subnet_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = await response.parse() + assert_matches_type(Router, router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_detach_subnet(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `router_id` but received ''"): + await async_client.cloud.networks.routers.with_raw_response.detach_subnet( + router_id="", + project_id=0, + region_id=0, + subnet_id="subnet_id", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + router = await async_client.cloud.networks.routers.get( + router_id="router_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Router, router, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.routers.with_raw_response.get( + router_id="router_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + router = await response.parse() + assert_matches_type(Router, router, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.routers.with_streaming_response.get( + router_id="router_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + router = await response.parse() + assert_matches_type(Router, router, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `router_id` but received ''"): + await async_client.cloud.networks.routers.with_raw_response.get( + router_id="", + project_id=0, + region_id=0, + ) diff --git a/tests/api_resources/cloud/networks/test_subnets.py b/tests/api_resources/cloud/networks/test_subnets.py new file mode 100644 index 00000000..dc315c0a --- /dev/null +++ b/tests/api_resources/cloud/networks/test_subnets.py @@ -0,0 +1,571 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import Subnet, TaskIDList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSubnets: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + subnet = client.cloud.networks.subnets.create( + project_id=1, + region_id=1, + cidr="192.168.10.0/24", + name="my subnet", + network_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) + assert_matches_type(TaskIDList, subnet, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + subnet = client.cloud.networks.subnets.create( + project_id=1, + region_id=1, + cidr="192.168.10.0/24", + name="my subnet", + network_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + connect_to_network_router=True, + dns_nameservers=["8.8.4.4", "1.1.1.1"], + enable_dhcp=True, + gateway_ip="192.168.10.1", + host_routes=[ + { + "destination": "10.0.3.0/24", + "nexthop": "10.0.0.13", + } + ], + ip_version=4, + router_id_to_connect="00000000-0000-4000-8000-000000000000", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, subnet, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.networks.subnets.with_raw_response.create( + project_id=1, + region_id=1, + cidr="192.168.10.0/24", + name="my subnet", + network_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subnet = response.parse() + assert_matches_type(TaskIDList, subnet, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.networks.subnets.with_streaming_response.create( + project_id=1, + region_id=1, + cidr="192.168.10.0/24", + name="my subnet", + network_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subnet = response.parse() + assert_matches_type(TaskIDList, subnet, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + subnet = client.cloud.networks.subnets.update( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + assert_matches_type(Subnet, subnet, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + subnet = client.cloud.networks.subnets.update( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + dns_nameservers=["8.8.4.4", "1.1.1.1"], + enable_dhcp=True, + gateway_ip="192.168.10.1", + host_routes=[ + { + "destination": "10.0.3.0/24", + "nexthop": "10.0.0.13", + } + ], + name="some_name", + tags={}, + ) + assert_matches_type(Subnet, subnet, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.networks.subnets.with_raw_response.update( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subnet = response.parse() + assert_matches_type(Subnet, subnet, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.networks.subnets.with_streaming_response.update( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subnet = response.parse() + assert_matches_type(Subnet, subnet, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `subnet_id` but received ''"): + client.cloud.networks.subnets.with_raw_response.update( + subnet_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + subnet = client.cloud.networks.subnets.list( + project_id=1, + region_id=1, + ) + assert_matches_type(SyncOffsetPage[Subnet], subnet, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + subnet = client.cloud.networks.subnets.list( + project_id=1, + region_id=1, + limit=1000, + network_id="b30d0de7-bca2-4c83-9c57-9e645bd2cc92", + offset=0, + order_by="name.asc", + tag_key=["key1", "key2"], + tag_key_value="tag_key_value", + ) + assert_matches_type(SyncOffsetPage[Subnet], subnet, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.networks.subnets.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subnet = response.parse() + assert_matches_type(SyncOffsetPage[Subnet], subnet, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.networks.subnets.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subnet = response.parse() + assert_matches_type(SyncOffsetPage[Subnet], subnet, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + subnet = client.cloud.networks.subnets.delete( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, subnet, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.networks.subnets.with_raw_response.delete( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subnet = response.parse() + assert_matches_type(TaskIDList, subnet, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.networks.subnets.with_streaming_response.delete( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subnet = response.parse() + assert_matches_type(TaskIDList, subnet, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `subnet_id` but received ''"): + client.cloud.networks.subnets.with_raw_response.delete( + subnet_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + subnet = client.cloud.networks.subnets.get( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + assert_matches_type(Subnet, subnet, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.networks.subnets.with_raw_response.get( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subnet = response.parse() + assert_matches_type(Subnet, subnet, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.networks.subnets.with_streaming_response.get( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subnet = response.parse() + assert_matches_type(Subnet, subnet, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `subnet_id` but received ''"): + client.cloud.networks.subnets.with_raw_response.get( + subnet_id="", + project_id=1, + region_id=1, + ) + + +class TestAsyncSubnets: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + subnet = await async_client.cloud.networks.subnets.create( + project_id=1, + region_id=1, + cidr="192.168.10.0/24", + name="my subnet", + network_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) + assert_matches_type(TaskIDList, subnet, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + subnet = await async_client.cloud.networks.subnets.create( + project_id=1, + region_id=1, + cidr="192.168.10.0/24", + name="my subnet", + network_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + connect_to_network_router=True, + dns_nameservers=["8.8.4.4", "1.1.1.1"], + enable_dhcp=True, + gateway_ip="192.168.10.1", + host_routes=[ + { + "destination": "10.0.3.0/24", + "nexthop": "10.0.0.13", + } + ], + ip_version=4, + router_id_to_connect="00000000-0000-4000-8000-000000000000", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, subnet, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.subnets.with_raw_response.create( + project_id=1, + region_id=1, + cidr="192.168.10.0/24", + name="my subnet", + network_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subnet = await response.parse() + assert_matches_type(TaskIDList, subnet, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.subnets.with_streaming_response.create( + project_id=1, + region_id=1, + cidr="192.168.10.0/24", + name="my subnet", + network_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subnet = await response.parse() + assert_matches_type(TaskIDList, subnet, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + subnet = await async_client.cloud.networks.subnets.update( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + assert_matches_type(Subnet, subnet, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + subnet = await async_client.cloud.networks.subnets.update( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + dns_nameservers=["8.8.4.4", "1.1.1.1"], + enable_dhcp=True, + gateway_ip="192.168.10.1", + host_routes=[ + { + "destination": "10.0.3.0/24", + "nexthop": "10.0.0.13", + } + ], + name="some_name", + tags={}, + ) + assert_matches_type(Subnet, subnet, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.subnets.with_raw_response.update( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subnet = await response.parse() + assert_matches_type(Subnet, subnet, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.subnets.with_streaming_response.update( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subnet = await response.parse() + assert_matches_type(Subnet, subnet, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `subnet_id` but received ''"): + await async_client.cloud.networks.subnets.with_raw_response.update( + subnet_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + subnet = await async_client.cloud.networks.subnets.list( + project_id=1, + region_id=1, + ) + assert_matches_type(AsyncOffsetPage[Subnet], subnet, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + subnet = await async_client.cloud.networks.subnets.list( + project_id=1, + region_id=1, + limit=1000, + network_id="b30d0de7-bca2-4c83-9c57-9e645bd2cc92", + offset=0, + order_by="name.asc", + tag_key=["key1", "key2"], + tag_key_value="tag_key_value", + ) + assert_matches_type(AsyncOffsetPage[Subnet], subnet, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.subnets.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subnet = await response.parse() + assert_matches_type(AsyncOffsetPage[Subnet], subnet, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.subnets.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subnet = await response.parse() + assert_matches_type(AsyncOffsetPage[Subnet], subnet, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + subnet = await async_client.cloud.networks.subnets.delete( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, subnet, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.subnets.with_raw_response.delete( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subnet = await response.parse() + assert_matches_type(TaskIDList, subnet, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.subnets.with_streaming_response.delete( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subnet = await response.parse() + assert_matches_type(TaskIDList, subnet, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `subnet_id` but received ''"): + await async_client.cloud.networks.subnets.with_raw_response.delete( + subnet_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + subnet = await async_client.cloud.networks.subnets.get( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + assert_matches_type(Subnet, subnet, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.subnets.with_raw_response.get( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subnet = await response.parse() + assert_matches_type(Subnet, subnet, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.subnets.with_streaming_response.get( + subnet_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subnet = await response.parse() + assert_matches_type(Subnet, subnet, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `subnet_id` but received ''"): + await async_client.cloud.networks.subnets.with_raw_response.get( + subnet_id="", + project_id=1, + region_id=1, + ) diff --git a/tests/api_resources/cloud/quotas/__init__.py b/tests/api_resources/cloud/quotas/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/quotas/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/quotas/test_requests.py b/tests/api_resources/cloud/quotas/test_requests.py new file mode 100644 index 00000000..00d49bcd --- /dev/null +++ b/tests/api_resources/cloud/quotas/test_requests.py @@ -0,0 +1,440 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud.quotas import RequestGetResponse, RequestListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRequests: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + request = client.cloud.quotas.requests.create( + description="Scale up mysql cluster", + requested_limits={}, + ) + assert request is None + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + request = client.cloud.quotas.requests.create( + description="Scale up mysql cluster", + requested_limits={ + "global_limits": { + "inference_cpu_millicore_count_limit": 0, + "inference_gpu_a100_count_limit": 0, + "inference_gpu_h100_count_limit": 0, + "inference_gpu_l40s_count_limit": 0, + "inference_instance_count_limit": 0, + "keypair_count_limit": 100, + "project_count_limit": 2, + }, + "regional_limits": [ + { + "baremetal_basic_count_limit": 0, + "baremetal_gpu_a100_count_limit": 0, + "baremetal_gpu_count_limit": 0, + "baremetal_gpu_h100_count_limit": 0, + "baremetal_gpu_h200_count_limit": 0, + "baremetal_gpu_l40s_count_limit": 0, + "baremetal_hf_count_limit": 0, + "baremetal_infrastructure_count_limit": 0, + "baremetal_network_count_limit": 0, + "baremetal_storage_count_limit": 0, + "caas_container_count_limit": 0, + "caas_cpu_count_limit": 0, + "caas_gpu_count_limit": 0, + "caas_ram_size_limit": 0, + "cluster_count_limit": 0, + "cpu_count_limit": 0, + "dbaas_postgres_cluster_count_limit": 0, + "external_ip_count_limit": 0, + "faas_cpu_count_limit": 0, + "faas_function_count_limit": 0, + "faas_namespace_count_limit": 0, + "faas_ram_size_limit": 0, + "firewall_count_limit": 0, + "floating_count_limit": 0, + "gpu_count_limit": 0, + "gpu_virtual_a100_count_limit": 0, + "gpu_virtual_h100_count_limit": 0, + "gpu_virtual_h200_count_limit": 0, + "gpu_virtual_l40s_count_limit": 0, + "image_count_limit": 0, + "image_size_limit": 0, + "ipu_count_limit": 0, + "laas_topic_count_limit": 0, + "loadbalancer_count_limit": 0, + "network_count_limit": 0, + "ram_limit": 0, + "region_id": 1, + "registry_count_limit": 0, + "registry_storage_limit": 0, + "router_count_limit": 0, + "secret_count_limit": 0, + "servergroup_count_limit": 0, + "sfs_count_limit": 0, + "sfs_size_limit": 0, + "shared_vm_count_limit": 0, + "snapshot_schedule_count_limit": 0, + "subnet_count_limit": 0, + "vm_count_limit": 0, + "volume_count_limit": 0, + "volume_size_limit": 0, + "volume_snapshots_count_limit": 0, + "volume_snapshots_size_limit": 0, + } + ], + }, + ) + assert request is None + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.quotas.requests.with_raw_response.create( + description="Scale up mysql cluster", + requested_limits={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + request = response.parse() + assert request is None + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.quotas.requests.with_streaming_response.create( + description="Scale up mysql cluster", + requested_limits={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + request = response.parse() + assert request is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + request = client.cloud.quotas.requests.list() + assert_matches_type(SyncOffsetPage[RequestListResponse], request, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + request = client.cloud.quotas.requests.list( + created_from=parse_datetime("2024-01-01T00:00:00Z"), + created_to=parse_datetime("2024-12-31T23:59:59Z"), + limit=1000, + offset=0, + request_ids=[1, 2, 3], + status=["done", "in progress"], + ) + assert_matches_type(SyncOffsetPage[RequestListResponse], request, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.quotas.requests.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + request = response.parse() + assert_matches_type(SyncOffsetPage[RequestListResponse], request, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.quotas.requests.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + request = response.parse() + assert_matches_type(SyncOffsetPage[RequestListResponse], request, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + request = client.cloud.quotas.requests.delete( + 3, + ) + assert request is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.quotas.requests.with_raw_response.delete( + 3, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + request = response.parse() + assert request is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.quotas.requests.with_streaming_response.delete( + 3, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + request = response.parse() + assert request is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + request = client.cloud.quotas.requests.get( + 3, + ) + assert_matches_type(RequestGetResponse, request, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.quotas.requests.with_raw_response.get( + 3, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + request = response.parse() + assert_matches_type(RequestGetResponse, request, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.quotas.requests.with_streaming_response.get( + 3, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + request = response.parse() + assert_matches_type(RequestGetResponse, request, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncRequests: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + request = await async_client.cloud.quotas.requests.create( + description="Scale up mysql cluster", + requested_limits={}, + ) + assert request is None + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + request = await async_client.cloud.quotas.requests.create( + description="Scale up mysql cluster", + requested_limits={ + "global_limits": { + "inference_cpu_millicore_count_limit": 0, + "inference_gpu_a100_count_limit": 0, + "inference_gpu_h100_count_limit": 0, + "inference_gpu_l40s_count_limit": 0, + "inference_instance_count_limit": 0, + "keypair_count_limit": 100, + "project_count_limit": 2, + }, + "regional_limits": [ + { + "baremetal_basic_count_limit": 0, + "baremetal_gpu_a100_count_limit": 0, + "baremetal_gpu_count_limit": 0, + "baremetal_gpu_h100_count_limit": 0, + "baremetal_gpu_h200_count_limit": 0, + "baremetal_gpu_l40s_count_limit": 0, + "baremetal_hf_count_limit": 0, + "baremetal_infrastructure_count_limit": 0, + "baremetal_network_count_limit": 0, + "baremetal_storage_count_limit": 0, + "caas_container_count_limit": 0, + "caas_cpu_count_limit": 0, + "caas_gpu_count_limit": 0, + "caas_ram_size_limit": 0, + "cluster_count_limit": 0, + "cpu_count_limit": 0, + "dbaas_postgres_cluster_count_limit": 0, + "external_ip_count_limit": 0, + "faas_cpu_count_limit": 0, + "faas_function_count_limit": 0, + "faas_namespace_count_limit": 0, + "faas_ram_size_limit": 0, + "firewall_count_limit": 0, + "floating_count_limit": 0, + "gpu_count_limit": 0, + "gpu_virtual_a100_count_limit": 0, + "gpu_virtual_h100_count_limit": 0, + "gpu_virtual_h200_count_limit": 0, + "gpu_virtual_l40s_count_limit": 0, + "image_count_limit": 0, + "image_size_limit": 0, + "ipu_count_limit": 0, + "laas_topic_count_limit": 0, + "loadbalancer_count_limit": 0, + "network_count_limit": 0, + "ram_limit": 0, + "region_id": 1, + "registry_count_limit": 0, + "registry_storage_limit": 0, + "router_count_limit": 0, + "secret_count_limit": 0, + "servergroup_count_limit": 0, + "sfs_count_limit": 0, + "sfs_size_limit": 0, + "shared_vm_count_limit": 0, + "snapshot_schedule_count_limit": 0, + "subnet_count_limit": 0, + "vm_count_limit": 0, + "volume_count_limit": 0, + "volume_size_limit": 0, + "volume_snapshots_count_limit": 0, + "volume_snapshots_size_limit": 0, + } + ], + }, + ) + assert request is None + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.quotas.requests.with_raw_response.create( + description="Scale up mysql cluster", + requested_limits={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + request = await response.parse() + assert request is None + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.quotas.requests.with_streaming_response.create( + description="Scale up mysql cluster", + requested_limits={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + request = await response.parse() + assert request is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + request = await async_client.cloud.quotas.requests.list() + assert_matches_type(AsyncOffsetPage[RequestListResponse], request, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + request = await async_client.cloud.quotas.requests.list( + created_from=parse_datetime("2024-01-01T00:00:00Z"), + created_to=parse_datetime("2024-12-31T23:59:59Z"), + limit=1000, + offset=0, + request_ids=[1, 2, 3], + status=["done", "in progress"], + ) + assert_matches_type(AsyncOffsetPage[RequestListResponse], request, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.quotas.requests.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + request = await response.parse() + assert_matches_type(AsyncOffsetPage[RequestListResponse], request, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.quotas.requests.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + request = await response.parse() + assert_matches_type(AsyncOffsetPage[RequestListResponse], request, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + request = await async_client.cloud.quotas.requests.delete( + 3, + ) + assert request is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.quotas.requests.with_raw_response.delete( + 3, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + request = await response.parse() + assert request is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.quotas.requests.with_streaming_response.delete( + 3, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + request = await response.parse() + assert request is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + request = await async_client.cloud.quotas.requests.get( + 3, + ) + assert_matches_type(RequestGetResponse, request, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.quotas.requests.with_raw_response.get( + 3, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + request = await response.parse() + assert_matches_type(RequestGetResponse, request, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.quotas.requests.with_streaming_response.get( + 3, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + request = await response.parse() + assert_matches_type(RequestGetResponse, request, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/registries/__init__.py b/tests/api_resources/cloud/registries/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/registries/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/registries/test_artifacts.py b/tests/api_resources/cloud/registries/test_artifacts.py new file mode 100644 index 00000000..2d602314 --- /dev/null +++ b/tests/api_resources/cloud/registries/test_artifacts.py @@ -0,0 +1,250 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.registries import RegistryArtifactList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestArtifacts: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + artifact = client.cloud.registries.artifacts.list( + repository_name="repository_name", + project_id=0, + region_id=0, + registry_id=0, + ) + assert_matches_type(RegistryArtifactList, artifact, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.registries.artifacts.with_raw_response.list( + repository_name="repository_name", + project_id=0, + region_id=0, + registry_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + artifact = response.parse() + assert_matches_type(RegistryArtifactList, artifact, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.registries.artifacts.with_streaming_response.list( + repository_name="repository_name", + project_id=0, + region_id=0, + registry_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + artifact = response.parse() + assert_matches_type(RegistryArtifactList, artifact, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `repository_name` but received ''"): + client.cloud.registries.artifacts.with_raw_response.list( + repository_name="", + project_id=0, + region_id=0, + registry_id=0, + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + artifact = client.cloud.registries.artifacts.delete( + digest="digest", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + ) + assert artifact is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.registries.artifacts.with_raw_response.delete( + digest="digest", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + artifact = response.parse() + assert artifact is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.registries.artifacts.with_streaming_response.delete( + digest="digest", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + artifact = response.parse() + assert artifact is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `repository_name` but received ''"): + client.cloud.registries.artifacts.with_raw_response.delete( + digest="digest", + project_id=0, + region_id=0, + registry_id=0, + repository_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `digest` but received ''"): + client.cloud.registries.artifacts.with_raw_response.delete( + digest="", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + ) + + +class TestAsyncArtifacts: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + artifact = await async_client.cloud.registries.artifacts.list( + repository_name="repository_name", + project_id=0, + region_id=0, + registry_id=0, + ) + assert_matches_type(RegistryArtifactList, artifact, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.artifacts.with_raw_response.list( + repository_name="repository_name", + project_id=0, + region_id=0, + registry_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + artifact = await response.parse() + assert_matches_type(RegistryArtifactList, artifact, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.artifacts.with_streaming_response.list( + repository_name="repository_name", + project_id=0, + region_id=0, + registry_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + artifact = await response.parse() + assert_matches_type(RegistryArtifactList, artifact, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `repository_name` but received ''"): + await async_client.cloud.registries.artifacts.with_raw_response.list( + repository_name="", + project_id=0, + region_id=0, + registry_id=0, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + artifact = await async_client.cloud.registries.artifacts.delete( + digest="digest", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + ) + assert artifact is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.artifacts.with_raw_response.delete( + digest="digest", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + artifact = await response.parse() + assert artifact is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.artifacts.with_streaming_response.delete( + digest="digest", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + artifact = await response.parse() + assert artifact is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `repository_name` but received ''"): + await async_client.cloud.registries.artifacts.with_raw_response.delete( + digest="digest", + project_id=0, + region_id=0, + registry_id=0, + repository_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `digest` but received ''"): + await async_client.cloud.registries.artifacts.with_raw_response.delete( + digest="", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + ) diff --git a/tests/api_resources/cloud/registries/test_repositories.py b/tests/api_resources/cloud/registries/test_repositories.py new file mode 100644 index 00000000..897e48d7 --- /dev/null +++ b/tests/api_resources/cloud/registries/test_repositories.py @@ -0,0 +1,198 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.registries import RegistryRepositoryList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRepositories: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + repository = client.cloud.registries.repositories.list( + registry_id=0, + project_id=0, + region_id=0, + ) + assert_matches_type(RegistryRepositoryList, repository, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.registries.repositories.with_raw_response.list( + registry_id=0, + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + repository = response.parse() + assert_matches_type(RegistryRepositoryList, repository, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.registries.repositories.with_streaming_response.list( + registry_id=0, + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + repository = response.parse() + assert_matches_type(RegistryRepositoryList, repository, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + repository = client.cloud.registries.repositories.delete( + repository_name="repository_name", + project_id=0, + region_id=0, + registry_id=0, + ) + assert repository is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.registries.repositories.with_raw_response.delete( + repository_name="repository_name", + project_id=0, + region_id=0, + registry_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + repository = response.parse() + assert repository is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.registries.repositories.with_streaming_response.delete( + repository_name="repository_name", + project_id=0, + region_id=0, + registry_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + repository = response.parse() + assert repository is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `repository_name` but received ''"): + client.cloud.registries.repositories.with_raw_response.delete( + repository_name="", + project_id=0, + region_id=0, + registry_id=0, + ) + + +class TestAsyncRepositories: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + repository = await async_client.cloud.registries.repositories.list( + registry_id=0, + project_id=0, + region_id=0, + ) + assert_matches_type(RegistryRepositoryList, repository, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.repositories.with_raw_response.list( + registry_id=0, + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + repository = await response.parse() + assert_matches_type(RegistryRepositoryList, repository, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.repositories.with_streaming_response.list( + registry_id=0, + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + repository = await response.parse() + assert_matches_type(RegistryRepositoryList, repository, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + repository = await async_client.cloud.registries.repositories.delete( + repository_name="repository_name", + project_id=0, + region_id=0, + registry_id=0, + ) + assert repository is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.repositories.with_raw_response.delete( + repository_name="repository_name", + project_id=0, + region_id=0, + registry_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + repository = await response.parse() + assert repository is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.repositories.with_streaming_response.delete( + repository_name="repository_name", + project_id=0, + region_id=0, + registry_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + repository = await response.parse() + assert repository is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `repository_name` but received ''"): + await async_client.cloud.registries.repositories.with_raw_response.delete( + repository_name="", + project_id=0, + region_id=0, + registry_id=0, + ) diff --git a/tests/api_resources/cloud/registries/test_tags.py b/tests/api_resources/cloud/registries/test_tags.py new file mode 100644 index 00000000..18010d41 --- /dev/null +++ b/tests/api_resources/cloud/registries/test_tags.py @@ -0,0 +1,178 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTags: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + tag = client.cloud.registries.tags.delete( + tag_name="tag_name", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + digest="digest", + ) + assert tag is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.registries.tags.with_raw_response.delete( + tag_name="tag_name", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + digest="digest", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + tag = response.parse() + assert tag is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.registries.tags.with_streaming_response.delete( + tag_name="tag_name", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + digest="digest", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + tag = response.parse() + assert tag is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `repository_name` but received ''"): + client.cloud.registries.tags.with_raw_response.delete( + tag_name="tag_name", + project_id=0, + region_id=0, + registry_id=0, + repository_name="", + digest="digest", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `digest` but received ''"): + client.cloud.registries.tags.with_raw_response.delete( + tag_name="tag_name", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + digest="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `tag_name` but received ''"): + client.cloud.registries.tags.with_raw_response.delete( + tag_name="", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + digest="digest", + ) + + +class TestAsyncTags: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + tag = await async_client.cloud.registries.tags.delete( + tag_name="tag_name", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + digest="digest", + ) + assert tag is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.tags.with_raw_response.delete( + tag_name="tag_name", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + digest="digest", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + tag = await response.parse() + assert tag is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.tags.with_streaming_response.delete( + tag_name="tag_name", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + digest="digest", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + tag = await response.parse() + assert tag is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `repository_name` but received ''"): + await async_client.cloud.registries.tags.with_raw_response.delete( + tag_name="tag_name", + project_id=0, + region_id=0, + registry_id=0, + repository_name="", + digest="digest", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `digest` but received ''"): + await async_client.cloud.registries.tags.with_raw_response.delete( + tag_name="tag_name", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + digest="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `tag_name` but received ''"): + await async_client.cloud.registries.tags.with_raw_response.delete( + tag_name="", + project_id=0, + region_id=0, + registry_id=0, + repository_name="repository_name", + digest="digest", + ) diff --git a/tests/api_resources/cloud/registries/test_users.py b/tests/api_resources/cloud/registries/test_users.py new file mode 100644 index 00000000..1167b206 --- /dev/null +++ b/tests/api_resources/cloud/registries/test_users.py @@ -0,0 +1,595 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.registries import ( + RegistryUser, + RegistryUserList, + RegistryUserCreated, + UserRefreshSecretResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestUsers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + user = client.cloud.registries.users.create( + registry_id=0, + project_id=0, + region_id=0, + duration=14, + name="user1", + ) + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + user = client.cloud.registries.users.create( + registry_id=0, + project_id=0, + region_id=0, + duration=14, + name="user1", + read_only=False, + secret="secret", + ) + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.registries.users.with_raw_response.create( + registry_id=0, + project_id=0, + region_id=0, + duration=14, + name="user1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.registries.users.with_streaming_response.create( + registry_id=0, + project_id=0, + region_id=0, + duration=14, + name="user1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + user = client.cloud.registries.users.update( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + duration=14, + ) + assert_matches_type(RegistryUser, user, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + user = client.cloud.registries.users.update( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + duration=14, + read_only=False, + ) + assert_matches_type(RegistryUser, user, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.registries.users.with_raw_response.update( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + duration=14, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(RegistryUser, user, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.registries.users.with_streaming_response.update( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + duration=14, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(RegistryUser, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + user = client.cloud.registries.users.list( + registry_id=0, + project_id=0, + region_id=0, + ) + assert_matches_type(RegistryUserList, user, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.registries.users.with_raw_response.list( + registry_id=0, + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(RegistryUserList, user, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.registries.users.with_streaming_response.list( + registry_id=0, + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(RegistryUserList, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + user = client.cloud.registries.users.delete( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + ) + assert user is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.registries.users.with_raw_response.delete( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert user is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.registries.users.with_streaming_response.delete( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert user is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_multiple(self, client: Gcore) -> None: + user = client.cloud.registries.users.create_multiple( + registry_id=0, + project_id=0, + region_id=0, + users=[ + { + "duration": -1, + "name": "user1", + } + ], + ) + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + @parametrize + def test_raw_response_create_multiple(self, client: Gcore) -> None: + response = client.cloud.registries.users.with_raw_response.create_multiple( + registry_id=0, + project_id=0, + region_id=0, + users=[ + { + "duration": -1, + "name": "user1", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + @parametrize + def test_streaming_response_create_multiple(self, client: Gcore) -> None: + with client.cloud.registries.users.with_streaming_response.create_multiple( + registry_id=0, + project_id=0, + region_id=0, + users=[ + { + "duration": -1, + "name": "user1", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_refresh_secret(self, client: Gcore) -> None: + user = client.cloud.registries.users.refresh_secret( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + ) + assert_matches_type(UserRefreshSecretResponse, user, path=["response"]) + + @parametrize + def test_raw_response_refresh_secret(self, client: Gcore) -> None: + response = client.cloud.registries.users.with_raw_response.refresh_secret( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserRefreshSecretResponse, user, path=["response"]) + + @parametrize + def test_streaming_response_refresh_secret(self, client: Gcore) -> None: + with client.cloud.registries.users.with_streaming_response.refresh_secret( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(UserRefreshSecretResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncUsers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + user = await async_client.cloud.registries.users.create( + registry_id=0, + project_id=0, + region_id=0, + duration=14, + name="user1", + ) + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + user = await async_client.cloud.registries.users.create( + registry_id=0, + project_id=0, + region_id=0, + duration=14, + name="user1", + read_only=False, + secret="secret", + ) + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.users.with_raw_response.create( + registry_id=0, + project_id=0, + region_id=0, + duration=14, + name="user1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.users.with_streaming_response.create( + registry_id=0, + project_id=0, + region_id=0, + duration=14, + name="user1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + user = await async_client.cloud.registries.users.update( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + duration=14, + ) + assert_matches_type(RegistryUser, user, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + user = await async_client.cloud.registries.users.update( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + duration=14, + read_only=False, + ) + assert_matches_type(RegistryUser, user, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.users.with_raw_response.update( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + duration=14, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert_matches_type(RegistryUser, user, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.users.with_streaming_response.update( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + duration=14, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(RegistryUser, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + user = await async_client.cloud.registries.users.list( + registry_id=0, + project_id=0, + region_id=0, + ) + assert_matches_type(RegistryUserList, user, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.users.with_raw_response.list( + registry_id=0, + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert_matches_type(RegistryUserList, user, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.users.with_streaming_response.list( + registry_id=0, + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(RegistryUserList, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + user = await async_client.cloud.registries.users.delete( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + ) + assert user is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.users.with_raw_response.delete( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert user is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.users.with_streaming_response.delete( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert user is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_multiple(self, async_client: AsyncGcore) -> None: + user = await async_client.cloud.registries.users.create_multiple( + registry_id=0, + project_id=0, + region_id=0, + users=[ + { + "duration": -1, + "name": "user1", + } + ], + ) + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + @parametrize + async def test_raw_response_create_multiple(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.users.with_raw_response.create_multiple( + registry_id=0, + project_id=0, + region_id=0, + users=[ + { + "duration": -1, + "name": "user1", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + @parametrize + async def test_streaming_response_create_multiple(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.users.with_streaming_response.create_multiple( + registry_id=0, + project_id=0, + region_id=0, + users=[ + { + "duration": -1, + "name": "user1", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(RegistryUserCreated, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_refresh_secret(self, async_client: AsyncGcore) -> None: + user = await async_client.cloud.registries.users.refresh_secret( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + ) + assert_matches_type(UserRefreshSecretResponse, user, path=["response"]) + + @parametrize + async def test_raw_response_refresh_secret(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.users.with_raw_response.refresh_secret( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert_matches_type(UserRefreshSecretResponse, user, path=["response"]) + + @parametrize + async def test_streaming_response_refresh_secret(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.users.with_streaming_response.refresh_secret( + user_id=0, + project_id=0, + region_id=0, + registry_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(UserRefreshSecretResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/reserved_fixed_ips/__init__.py b/tests/api_resources/cloud/reserved_fixed_ips/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/reserved_fixed_ips/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/reserved_fixed_ips/test_vip.py b/tests/api_resources/cloud/reserved_fixed_ips/test_vip.py new file mode 100644 index 00000000..1b905f1f --- /dev/null +++ b/tests/api_resources/cloud/reserved_fixed_ips/test_vip.py @@ -0,0 +1,124 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import ReservedFixedIP + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestVip: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_toggle(self, client: Gcore) -> None: + vip = client.cloud.reserved_fixed_ips.vip.toggle( + port_id="port_id", + project_id=0, + region_id=0, + is_vip=True, + ) + assert_matches_type(ReservedFixedIP, vip, path=["response"]) + + @parametrize + def test_raw_response_toggle(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.vip.with_raw_response.toggle( + port_id="port_id", + project_id=0, + region_id=0, + is_vip=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vip = response.parse() + assert_matches_type(ReservedFixedIP, vip, path=["response"]) + + @parametrize + def test_streaming_response_toggle(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.vip.with_streaming_response.toggle( + port_id="port_id", + project_id=0, + region_id=0, + is_vip=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vip = response.parse() + assert_matches_type(ReservedFixedIP, vip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_toggle(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + client.cloud.reserved_fixed_ips.vip.with_raw_response.toggle( + port_id="", + project_id=0, + region_id=0, + is_vip=True, + ) + + +class TestAsyncVip: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_toggle(self, async_client: AsyncGcore) -> None: + vip = await async_client.cloud.reserved_fixed_ips.vip.toggle( + port_id="port_id", + project_id=0, + region_id=0, + is_vip=True, + ) + assert_matches_type(ReservedFixedIP, vip, path=["response"]) + + @parametrize + async def test_raw_response_toggle(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.vip.with_raw_response.toggle( + port_id="port_id", + project_id=0, + region_id=0, + is_vip=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vip = await response.parse() + assert_matches_type(ReservedFixedIP, vip, path=["response"]) + + @parametrize + async def test_streaming_response_toggle(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.vip.with_streaming_response.toggle( + port_id="port_id", + project_id=0, + region_id=0, + is_vip=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vip = await response.parse() + assert_matches_type(ReservedFixedIP, vip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_toggle(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + await async_client.cloud.reserved_fixed_ips.vip.with_raw_response.toggle( + port_id="", + project_id=0, + region_id=0, + is_vip=True, + ) diff --git a/tests/api_resources/cloud/reserved_fixed_ips/vip/__init__.py b/tests/api_resources/cloud/reserved_fixed_ips/vip/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/reserved_fixed_ips/vip/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/reserved_fixed_ips/vip/test_candidate_ports.py b/tests/api_resources/cloud/reserved_fixed_ips/vip/test_candidate_ports.py new file mode 100644 index 00000000..cc679c0e --- /dev/null +++ b/tests/api_resources/cloud/reserved_fixed_ips/vip/test_candidate_ports.py @@ -0,0 +1,116 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.reserved_fixed_ips.vip import CandidatePortList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCandidatePorts: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + candidate_port = client.cloud.reserved_fixed_ips.vip.candidate_ports.list( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(CandidatePortList, candidate_port, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.vip.candidate_ports.with_raw_response.list( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + candidate_port = response.parse() + assert_matches_type(CandidatePortList, candidate_port, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.vip.candidate_ports.with_streaming_response.list( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + candidate_port = response.parse() + assert_matches_type(CandidatePortList, candidate_port, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + client.cloud.reserved_fixed_ips.vip.candidate_ports.with_raw_response.list( + port_id="", + project_id=0, + region_id=0, + ) + + +class TestAsyncCandidatePorts: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + candidate_port = await async_client.cloud.reserved_fixed_ips.vip.candidate_ports.list( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(CandidatePortList, candidate_port, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.vip.candidate_ports.with_raw_response.list( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + candidate_port = await response.parse() + assert_matches_type(CandidatePortList, candidate_port, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.vip.candidate_ports.with_streaming_response.list( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + candidate_port = await response.parse() + assert_matches_type(CandidatePortList, candidate_port, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + await async_client.cloud.reserved_fixed_ips.vip.candidate_ports.with_raw_response.list( + port_id="", + project_id=0, + region_id=0, + ) diff --git a/tests/api_resources/cloud/reserved_fixed_ips/vip/test_connected_ports.py b/tests/api_resources/cloud/reserved_fixed_ips/vip/test_connected_ports.py new file mode 100644 index 00000000..7c47c319 --- /dev/null +++ b/tests/api_resources/cloud/reserved_fixed_ips/vip/test_connected_ports.py @@ -0,0 +1,342 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud.reserved_fixed_ips.vip import ( + ConnectedPortList, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestConnectedPorts: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + connected_port = client.cloud.reserved_fixed_ips.vip.connected_ports.list( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.vip.connected_ports.with_raw_response.list( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connected_port = response.parse() + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.vip.connected_ports.with_streaming_response.list( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connected_port = response.parse() + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + client.cloud.reserved_fixed_ips.vip.connected_ports.with_raw_response.list( + port_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_add(self, client: Gcore) -> None: + connected_port = client.cloud.reserved_fixed_ips.vip.connected_ports.add( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + def test_method_add_with_all_params(self, client: Gcore) -> None: + connected_port = client.cloud.reserved_fixed_ips.vip.connected_ports.add( + port_id="port_id", + project_id=0, + region_id=0, + port_ids=["351b0dd7-ca09-431c-be53-935db3785067", "bc688791-f1b0-44eb-97d4-07697294b1e1"], + ) + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + def test_raw_response_add(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.vip.connected_ports.with_raw_response.add( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connected_port = response.parse() + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + def test_streaming_response_add(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.vip.connected_ports.with_streaming_response.add( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connected_port = response.parse() + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_add(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + client.cloud.reserved_fixed_ips.vip.connected_ports.with_raw_response.add( + port_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + connected_port = client.cloud.reserved_fixed_ips.vip.connected_ports.replace( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + connected_port = client.cloud.reserved_fixed_ips.vip.connected_ports.replace( + port_id="port_id", + project_id=0, + region_id=0, + port_ids=["351b0dd7-ca09-431c-be53-935db3785067", "bc688791-f1b0-44eb-97d4-07697294b1e1"], + ) + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.vip.connected_ports.with_raw_response.replace( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connected_port = response.parse() + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.vip.connected_ports.with_streaming_response.replace( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connected_port = response.parse() + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_replace(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + client.cloud.reserved_fixed_ips.vip.connected_ports.with_raw_response.replace( + port_id="", + project_id=0, + region_id=0, + ) + + +class TestAsyncConnectedPorts: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + connected_port = await async_client.cloud.reserved_fixed_ips.vip.connected_ports.list( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.vip.connected_ports.with_raw_response.list( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connected_port = await response.parse() + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.vip.connected_ports.with_streaming_response.list( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connected_port = await response.parse() + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + await async_client.cloud.reserved_fixed_ips.vip.connected_ports.with_raw_response.list( + port_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_add(self, async_client: AsyncGcore) -> None: + connected_port = await async_client.cloud.reserved_fixed_ips.vip.connected_ports.add( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + async def test_method_add_with_all_params(self, async_client: AsyncGcore) -> None: + connected_port = await async_client.cloud.reserved_fixed_ips.vip.connected_ports.add( + port_id="port_id", + project_id=0, + region_id=0, + port_ids=["351b0dd7-ca09-431c-be53-935db3785067", "bc688791-f1b0-44eb-97d4-07697294b1e1"], + ) + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + async def test_raw_response_add(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.vip.connected_ports.with_raw_response.add( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connected_port = await response.parse() + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + async def test_streaming_response_add(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.vip.connected_ports.with_streaming_response.add( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connected_port = await response.parse() + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_add(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + await async_client.cloud.reserved_fixed_ips.vip.connected_ports.with_raw_response.add( + port_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + connected_port = await async_client.cloud.reserved_fixed_ips.vip.connected_ports.replace( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + connected_port = await async_client.cloud.reserved_fixed_ips.vip.connected_ports.replace( + port_id="port_id", + project_id=0, + region_id=0, + port_ids=["351b0dd7-ca09-431c-be53-935db3785067", "bc688791-f1b0-44eb-97d4-07697294b1e1"], + ) + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.vip.connected_ports.with_raw_response.replace( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connected_port = await response.parse() + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.vip.connected_ports.with_streaming_response.replace( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connected_port = await response.parse() + assert_matches_type(ConnectedPortList, connected_port, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_replace(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + await async_client.cloud.reserved_fixed_ips.vip.connected_ports.with_raw_response.replace( + port_id="", + project_id=0, + region_id=0, + ) diff --git a/tests/api_resources/cloud/security_groups/__init__.py b/tests/api_resources/cloud/security_groups/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/security_groups/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/security_groups/test_rules.py b/tests/api_resources/cloud/security_groups/test_rules.py new file mode 100644 index 00000000..ddd3a5d9 --- /dev/null +++ b/tests/api_resources/cloud/security_groups/test_rules.py @@ -0,0 +1,434 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import SecurityGroupRule + +# pyright: reportDeprecated=false + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRules: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + rule = client.cloud.security_groups.rules.create( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + ) + + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + rule = client.cloud.security_groups.rules.create( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + description="Some description", + ethertype="IPv4", + port_range_max=80, + port_range_min=80, + protocol="tcp", + remote_group_id="00000000-0000-4000-8000-000000000000", + remote_ip_prefix="10.0.0.0/8", + ) + + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + response = client.cloud.security_groups.rules.with_raw_response.create( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with client.cloud.security_groups.rules.with_streaming_response.create( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.cloud.security_groups.rules.with_raw_response.create( + group_id="", + project_id=1, + region_id=1, + direction="ingress", + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + rule = client.cloud.security_groups.rules.delete( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + + assert rule is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + response = client.cloud.security_groups.rules.with_raw_response.delete( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert rule is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with client.cloud.security_groups.rules.with_streaming_response.delete( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rule_id` but received ''"): + client.cloud.security_groups.rules.with_raw_response.delete( + rule_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + rule = client.cloud.security_groups.rules.replace( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + security_group_id="00000000-0000-4000-8000-000000000000", + ) + + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + rule = client.cloud.security_groups.rules.replace( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + security_group_id="00000000-0000-4000-8000-000000000000", + description="Some description", + ethertype="IPv4", + port_range_max=80, + port_range_min=80, + protocol="tcp", + remote_group_id="00000000-0000-4000-8000-000000000000", + remote_ip_prefix="10.0.0.0/8", + ) + + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + response = client.cloud.security_groups.rules.with_raw_response.replace( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + security_group_id="00000000-0000-4000-8000-000000000000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = response.parse() + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with client.cloud.security_groups.rules.with_streaming_response.replace( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + security_group_id="00000000-0000-4000-8000-000000000000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = response.parse() + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_replace(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rule_id` but received ''"): + client.cloud.security_groups.rules.with_raw_response.replace( + rule_id="", + project_id=1, + region_id=1, + direction="ingress", + security_group_id="00000000-0000-4000-8000-000000000000", + ) + + +class TestAsyncRules: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + rule = await async_client.cloud.security_groups.rules.create( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + ) + + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + rule = await async_client.cloud.security_groups.rules.create( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + description="Some description", + ethertype="IPv4", + port_range_max=80, + port_range_min=80, + protocol="tcp", + remote_group_id="00000000-0000-4000-8000-000000000000", + remote_ip_prefix="10.0.0.0/8", + ) + + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + response = await async_client.cloud.security_groups.rules.with_raw_response.create( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + async with async_client.cloud.security_groups.rules.with_streaming_response.create( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.cloud.security_groups.rules.with_raw_response.create( + group_id="", + project_id=1, + region_id=1, + direction="ingress", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + rule = await async_client.cloud.security_groups.rules.delete( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + + assert rule is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + response = await async_client.cloud.security_groups.rules.with_raw_response.delete( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert rule is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + async with async_client.cloud.security_groups.rules.with_streaming_response.delete( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rule_id` but received ''"): + await async_client.cloud.security_groups.rules.with_raw_response.delete( + rule_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + rule = await async_client.cloud.security_groups.rules.replace( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + security_group_id="00000000-0000-4000-8000-000000000000", + ) + + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + rule = await async_client.cloud.security_groups.rules.replace( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + security_group_id="00000000-0000-4000-8000-000000000000", + description="Some description", + ethertype="IPv4", + port_range_max=80, + port_range_min=80, + protocol="tcp", + remote_group_id="00000000-0000-4000-8000-000000000000", + remote_ip_prefix="10.0.0.0/8", + ) + + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + response = await async_client.cloud.security_groups.rules.with_raw_response.replace( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + security_group_id="00000000-0000-4000-8000-000000000000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rule = await response.parse() + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + async with async_client.cloud.security_groups.rules.with_streaming_response.replace( + rule_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + direction="ingress", + security_group_id="00000000-0000-4000-8000-000000000000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rule = await response.parse() + assert_matches_type(SecurityGroupRule, rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_replace(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rule_id` but received ''"): + await async_client.cloud.security_groups.rules.with_raw_response.replace( + rule_id="", + project_id=1, + region_id=1, + direction="ingress", + security_group_id="00000000-0000-4000-8000-000000000000", + ) diff --git a/tests/api_resources/cloud/test_audit_logs.py b/tests/api_resources/cloud/test_audit_logs.py new file mode 100644 index 00000000..924f869c --- /dev/null +++ b/tests/api_resources/cloud/test_audit_logs.py @@ -0,0 +1,116 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import AuditLogEntry + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAuditLogs: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + audit_log = client.cloud.audit_logs.list() + assert_matches_type(SyncOffsetPage[AuditLogEntry], audit_log, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + audit_log = client.cloud.audit_logs.list( + action_type=["activate", "delete"], + api_group=["ai_cluster", "image"], + from_timestamp=parse_datetime("2019-11-14T10:30:32Z"), + limit=1000, + offset=0, + order_by="asc", + project_id=[1, 2, 3], + region_id=[1, 2, 3], + resource_id=["string"], + search_field="default", + sorting="asc", + source_user_ips=["203.0.113.42", "192.168.1.100"], + to_timestamp=parse_datetime("2019-11-14T10:30:32Z"), + user_agents=["Mozilla/5.0", "MyApp/1.0.0"], + ) + assert_matches_type(SyncOffsetPage[AuditLogEntry], audit_log, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.audit_logs.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + audit_log = response.parse() + assert_matches_type(SyncOffsetPage[AuditLogEntry], audit_log, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.audit_logs.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + audit_log = response.parse() + assert_matches_type(SyncOffsetPage[AuditLogEntry], audit_log, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAuditLogs: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + audit_log = await async_client.cloud.audit_logs.list() + assert_matches_type(AsyncOffsetPage[AuditLogEntry], audit_log, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + audit_log = await async_client.cloud.audit_logs.list( + action_type=["activate", "delete"], + api_group=["ai_cluster", "image"], + from_timestamp=parse_datetime("2019-11-14T10:30:32Z"), + limit=1000, + offset=0, + order_by="asc", + project_id=[1, 2, 3], + region_id=[1, 2, 3], + resource_id=["string"], + search_field="default", + sorting="asc", + source_user_ips=["203.0.113.42", "192.168.1.100"], + to_timestamp=parse_datetime("2019-11-14T10:30:32Z"), + user_agents=["Mozilla/5.0", "MyApp/1.0.0"], + ) + assert_matches_type(AsyncOffsetPage[AuditLogEntry], audit_log, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.audit_logs.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + audit_log = await response.parse() + assert_matches_type(AsyncOffsetPage[AuditLogEntry], audit_log, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.audit_logs.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + audit_log = await response.parse() + assert_matches_type(AsyncOffsetPage[AuditLogEntry], audit_log, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/test_billing_reservations.py b/tests/api_resources/cloud/test_billing_reservations.py new file mode 100644 index 00000000..28dd8870 --- /dev/null +++ b/tests/api_resources/cloud/test_billing_reservations.py @@ -0,0 +1,94 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import BillingReservations + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBillingReservations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + billing_reservation = client.cloud.billing_reservations.list() + assert_matches_type(BillingReservations, billing_reservation, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + billing_reservation = client.cloud.billing_reservations.list( + metric_name="metric_name", + order_by="active_from.asc", + region_id=0, + show_inactive=True, + ) + assert_matches_type(BillingReservations, billing_reservation, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.billing_reservations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + billing_reservation = response.parse() + assert_matches_type(BillingReservations, billing_reservation, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.billing_reservations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + billing_reservation = response.parse() + assert_matches_type(BillingReservations, billing_reservation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncBillingReservations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + billing_reservation = await async_client.cloud.billing_reservations.list() + assert_matches_type(BillingReservations, billing_reservation, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + billing_reservation = await async_client.cloud.billing_reservations.list( + metric_name="metric_name", + order_by="active_from.asc", + region_id=0, + show_inactive=True, + ) + assert_matches_type(BillingReservations, billing_reservation, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.billing_reservations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + billing_reservation = await response.parse() + assert_matches_type(BillingReservations, billing_reservation, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.billing_reservations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + billing_reservation = await response.parse() + assert_matches_type(BillingReservations, billing_reservation, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/test_cost_reports.py b/tests/api_resources/cloud/test_cost_reports.py new file mode 100644 index 00000000..1e3a60b8 --- /dev/null +++ b/tests/api_resources/cloud/test_cost_reports.py @@ -0,0 +1,443 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.types.cloud import ( + CostReportDetailed, + CostReportAggregated, + CostReportAggregatedMonthly, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCostReports: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_aggregated(self, client: Gcore) -> None: + cost_report = client.cloud.cost_reports.get_aggregated( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) + assert_matches_type(CostReportAggregated, cost_report, path=["response"]) + + @parametrize + def test_method_get_aggregated_with_all_params(self, client: Gcore) -> None: + cost_report = client.cloud.cost_reports.get_aggregated( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + enable_last_day=False, + projects=[16, 17, 18, 19, 20], + regions=[1, 2, 3], + response_format="csv_totals", + rounding=True, + schema_filter={ + "field": "flavor", + "type": "instance", + "values": ["g1-standard-1-2"], + }, + tags={ + "conditions": [ + { + "key": "os_version", + "strict": True, + "value": "22.04", + }, + { + "key": "os_version", + "strict": True, + "value": "23.04", + }, + ], + "condition_type": "OR", + }, + types=["egress_traffic", "instance"], + ) + assert_matches_type(CostReportAggregated, cost_report, path=["response"]) + + @parametrize + def test_raw_response_get_aggregated(self, client: Gcore) -> None: + response = client.cloud.cost_reports.with_raw_response.get_aggregated( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cost_report = response.parse() + assert_matches_type(CostReportAggregated, cost_report, path=["response"]) + + @parametrize + def test_streaming_response_get_aggregated(self, client: Gcore) -> None: + with client.cloud.cost_reports.with_streaming_response.get_aggregated( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cost_report = response.parse() + assert_matches_type(CostReportAggregated, cost_report, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_aggregated_monthly(self, client: Gcore) -> None: + cost_report = client.cloud.cost_reports.get_aggregated_monthly() + assert_matches_type(CostReportAggregatedMonthly, cost_report, path=["response"]) + + @parametrize + def test_method_get_aggregated_monthly_with_all_params(self, client: Gcore) -> None: + cost_report = client.cloud.cost_reports.get_aggregated_monthly( + regions=[1, 2, 3], + response_format="csv_totals", + rounding=True, + schema_filter={ + "field": "flavor", + "type": "instance", + "values": ["g1-standard-1-2"], + }, + tags={ + "conditions": [ + { + "key": "os_version", + "strict": True, + "value": "22.04", + }, + { + "key": "os_version", + "strict": True, + "value": "23.04", + }, + ], + "condition_type": "OR", + }, + time_from=parse_datetime("2019-12-27T18:11:19.117Z"), + time_to=parse_datetime("2019-12-27T18:11:19.117Z"), + types=["egress_traffic", "instance"], + year_month="2024-08", + ) + assert_matches_type(CostReportAggregatedMonthly, cost_report, path=["response"]) + + @parametrize + def test_raw_response_get_aggregated_monthly(self, client: Gcore) -> None: + response = client.cloud.cost_reports.with_raw_response.get_aggregated_monthly() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cost_report = response.parse() + assert_matches_type(CostReportAggregatedMonthly, cost_report, path=["response"]) + + @parametrize + def test_streaming_response_get_aggregated_monthly(self, client: Gcore) -> None: + with client.cloud.cost_reports.with_streaming_response.get_aggregated_monthly() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cost_report = response.parse() + assert_matches_type(CostReportAggregatedMonthly, cost_report, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_detailed(self, client: Gcore) -> None: + cost_report = client.cloud.cost_reports.get_detailed( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) + assert_matches_type(CostReportDetailed, cost_report, path=["response"]) + + @parametrize + def test_method_get_detailed_with_all_params(self, client: Gcore) -> None: + cost_report = client.cloud.cost_reports.get_detailed( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + enable_last_day=False, + limit=10, + offset=0, + projects=[16, 17, 18, 19, 20], + regions=[1, 2, 3], + response_format="csv_records", + rounding=True, + schema_filter={ + "field": "flavor", + "type": "instance", + "values": ["g1-standard-1-2"], + }, + sorting=[ + { + "billing_value": "asc", + "first_seen": "asc", + "last_name": "asc", + "last_seen": "asc", + "project": "asc", + "region": "asc", + "type": "asc", + } + ], + tags={ + "conditions": [ + { + "key": "os_version", + "strict": True, + "value": "22.04", + }, + { + "key": "os_version", + "strict": True, + "value": "23.04", + }, + ], + "condition_type": "OR", + }, + types=["egress_traffic", "instance"], + ) + assert_matches_type(CostReportDetailed, cost_report, path=["response"]) + + @parametrize + def test_raw_response_get_detailed(self, client: Gcore) -> None: + response = client.cloud.cost_reports.with_raw_response.get_detailed( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cost_report = response.parse() + assert_matches_type(CostReportDetailed, cost_report, path=["response"]) + + @parametrize + def test_streaming_response_get_detailed(self, client: Gcore) -> None: + with client.cloud.cost_reports.with_streaming_response.get_detailed( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cost_report = response.parse() + assert_matches_type(CostReportDetailed, cost_report, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncCostReports: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_aggregated(self, async_client: AsyncGcore) -> None: + cost_report = await async_client.cloud.cost_reports.get_aggregated( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) + assert_matches_type(CostReportAggregated, cost_report, path=["response"]) + + @parametrize + async def test_method_get_aggregated_with_all_params(self, async_client: AsyncGcore) -> None: + cost_report = await async_client.cloud.cost_reports.get_aggregated( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + enable_last_day=False, + projects=[16, 17, 18, 19, 20], + regions=[1, 2, 3], + response_format="csv_totals", + rounding=True, + schema_filter={ + "field": "flavor", + "type": "instance", + "values": ["g1-standard-1-2"], + }, + tags={ + "conditions": [ + { + "key": "os_version", + "strict": True, + "value": "22.04", + }, + { + "key": "os_version", + "strict": True, + "value": "23.04", + }, + ], + "condition_type": "OR", + }, + types=["egress_traffic", "instance"], + ) + assert_matches_type(CostReportAggregated, cost_report, path=["response"]) + + @parametrize + async def test_raw_response_get_aggregated(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.cost_reports.with_raw_response.get_aggregated( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cost_report = await response.parse() + assert_matches_type(CostReportAggregated, cost_report, path=["response"]) + + @parametrize + async def test_streaming_response_get_aggregated(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.cost_reports.with_streaming_response.get_aggregated( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cost_report = await response.parse() + assert_matches_type(CostReportAggregated, cost_report, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_aggregated_monthly(self, async_client: AsyncGcore) -> None: + cost_report = await async_client.cloud.cost_reports.get_aggregated_monthly() + assert_matches_type(CostReportAggregatedMonthly, cost_report, path=["response"]) + + @parametrize + async def test_method_get_aggregated_monthly_with_all_params(self, async_client: AsyncGcore) -> None: + cost_report = await async_client.cloud.cost_reports.get_aggregated_monthly( + regions=[1, 2, 3], + response_format="csv_totals", + rounding=True, + schema_filter={ + "field": "flavor", + "type": "instance", + "values": ["g1-standard-1-2"], + }, + tags={ + "conditions": [ + { + "key": "os_version", + "strict": True, + "value": "22.04", + }, + { + "key": "os_version", + "strict": True, + "value": "23.04", + }, + ], + "condition_type": "OR", + }, + time_from=parse_datetime("2019-12-27T18:11:19.117Z"), + time_to=parse_datetime("2019-12-27T18:11:19.117Z"), + types=["egress_traffic", "instance"], + year_month="2024-08", + ) + assert_matches_type(CostReportAggregatedMonthly, cost_report, path=["response"]) + + @parametrize + async def test_raw_response_get_aggregated_monthly(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.cost_reports.with_raw_response.get_aggregated_monthly() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cost_report = await response.parse() + assert_matches_type(CostReportAggregatedMonthly, cost_report, path=["response"]) + + @parametrize + async def test_streaming_response_get_aggregated_monthly(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.cost_reports.with_streaming_response.get_aggregated_monthly() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cost_report = await response.parse() + assert_matches_type(CostReportAggregatedMonthly, cost_report, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_detailed(self, async_client: AsyncGcore) -> None: + cost_report = await async_client.cloud.cost_reports.get_detailed( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) + assert_matches_type(CostReportDetailed, cost_report, path=["response"]) + + @parametrize + async def test_method_get_detailed_with_all_params(self, async_client: AsyncGcore) -> None: + cost_report = await async_client.cloud.cost_reports.get_detailed( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + enable_last_day=False, + limit=10, + offset=0, + projects=[16, 17, 18, 19, 20], + regions=[1, 2, 3], + response_format="csv_records", + rounding=True, + schema_filter={ + "field": "flavor", + "type": "instance", + "values": ["g1-standard-1-2"], + }, + sorting=[ + { + "billing_value": "asc", + "first_seen": "asc", + "last_name": "asc", + "last_seen": "asc", + "project": "asc", + "region": "asc", + "type": "asc", + } + ], + tags={ + "conditions": [ + { + "key": "os_version", + "strict": True, + "value": "22.04", + }, + { + "key": "os_version", + "strict": True, + "value": "23.04", + }, + ], + "condition_type": "OR", + }, + types=["egress_traffic", "instance"], + ) + assert_matches_type(CostReportDetailed, cost_report, path=["response"]) + + @parametrize + async def test_raw_response_get_detailed(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.cost_reports.with_raw_response.get_detailed( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cost_report = await response.parse() + assert_matches_type(CostReportDetailed, cost_report, path=["response"]) + + @parametrize + async def test_streaming_response_get_detailed(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.cost_reports.with_streaming_response.get_detailed( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cost_report = await response.parse() + assert_matches_type(CostReportDetailed, cost_report, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/test_file_shares.py b/tests/api_resources/cloud/test_file_shares.py new file mode 100644 index 00000000..74d9a584 --- /dev/null +++ b/tests/api_resources/cloud/test_file_shares.py @@ -0,0 +1,792 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import ( + FileShare, + TaskIDList, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFileShares: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create_overload_1(self, client: Gcore) -> None: + file_share = client.cloud.file_shares.create( + project_id=1, + region_id=1, + name="test-share-file-system", + network={"network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8"}, + protocol="NFS", + size=5, + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_1(self, client: Gcore) -> None: + file_share = client.cloud.file_shares.create( + project_id=1, + region_id=1, + name="test-share-file-system", + network={ + "network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8", + "subnet_id": "91200a6c-07e0-42aa-98da-32d1f6545ae7", + }, + protocol="NFS", + size=5, + access=[ + { + "access_mode": "ro", + "ip_address": "10.0.0.1", + } + ], + tags={"my-tag": "my-tag-value"}, + type_name="standard", + volume_type="default_share_type", + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + def test_raw_response_create_overload_1(self, client: Gcore) -> None: + response = client.cloud.file_shares.with_raw_response.create( + project_id=1, + region_id=1, + name="test-share-file-system", + network={"network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8"}, + protocol="NFS", + size=5, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_1(self, client: Gcore) -> None: + with client.cloud.file_shares.with_streaming_response.create( + project_id=1, + region_id=1, + name="test-share-file-system", + network={"network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8"}, + protocol="NFS", + size=5, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_2(self, client: Gcore) -> None: + file_share = client.cloud.file_shares.create( + project_id=1, + region_id=1, + name="test-share-file-system", + protocol="NFS", + size=5, + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_2(self, client: Gcore) -> None: + file_share = client.cloud.file_shares.create( + project_id=1, + region_id=1, + name="test-share-file-system", + protocol="NFS", + size=5, + share_settings={ + "allowed_characters": "LCD", + "path_length": "LCD", + "root_squash": True, + }, + tags={"my-tag": "my-tag-value"}, + type_name="vast", + volume_type="vast_share_type", + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + def test_raw_response_create_overload_2(self, client: Gcore) -> None: + response = client.cloud.file_shares.with_raw_response.create( + project_id=1, + region_id=1, + name="test-share-file-system", + protocol="NFS", + size=5, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_2(self, client: Gcore) -> None: + with client.cloud.file_shares.with_streaming_response.create( + project_id=1, + region_id=1, + name="test-share-file-system", + protocol="NFS", + size=5, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + file_share = client.cloud.file_shares.update( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + file_share = client.cloud.file_shares.update( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + name="some_name", + share_settings={ + "allowed_characters": "LCD", + "path_length": "LCD", + "root_squash": True, + }, + tags={}, + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.file_shares.with_raw_response.update( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.file_shares.with_streaming_response.update( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + client.cloud.file_shares.with_raw_response.update( + file_share_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + file_share = client.cloud.file_shares.list( + project_id=1, + region_id=1, + ) + assert_matches_type(SyncOffsetPage[FileShare], file_share, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + file_share = client.cloud.file_shares.list( + project_id=1, + region_id=1, + limit=1000, + name="test-sfs", + offset=0, + type_name="standard", + ) + assert_matches_type(SyncOffsetPage[FileShare], file_share, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.file_shares.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = response.parse() + assert_matches_type(SyncOffsetPage[FileShare], file_share, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.file_shares.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = response.parse() + assert_matches_type(SyncOffsetPage[FileShare], file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + file_share = client.cloud.file_shares.delete( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.file_shares.with_raw_response.delete( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.file_shares.with_streaming_response.delete( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + client.cloud.file_shares.with_raw_response.delete( + file_share_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + file_share = client.cloud.file_shares.get( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + assert_matches_type(FileShare, file_share, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.file_shares.with_raw_response.get( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = response.parse() + assert_matches_type(FileShare, file_share, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.file_shares.with_streaming_response.get( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = response.parse() + assert_matches_type(FileShare, file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + client.cloud.file_shares.with_raw_response.get( + file_share_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_resize(self, client: Gcore) -> None: + file_share = client.cloud.file_shares.resize( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + size=5, + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + def test_raw_response_resize(self, client: Gcore) -> None: + response = client.cloud.file_shares.with_raw_response.resize( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + size=5, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + def test_streaming_response_resize(self, client: Gcore) -> None: + with client.cloud.file_shares.with_streaming_response.resize( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + size=5, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_resize(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + client.cloud.file_shares.with_raw_response.resize( + file_share_id="", + project_id=1, + region_id=1, + size=5, + ) + + +class TestAsyncFileShares: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create_overload_1(self, async_client: AsyncGcore) -> None: + file_share = await async_client.cloud.file_shares.create( + project_id=1, + region_id=1, + name="test-share-file-system", + network={"network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8"}, + protocol="NFS", + size=5, + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_1(self, async_client: AsyncGcore) -> None: + file_share = await async_client.cloud.file_shares.create( + project_id=1, + region_id=1, + name="test-share-file-system", + network={ + "network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8", + "subnet_id": "91200a6c-07e0-42aa-98da-32d1f6545ae7", + }, + protocol="NFS", + size=5, + access=[ + { + "access_mode": "ro", + "ip_address": "10.0.0.1", + } + ], + tags={"my-tag": "my-tag-value"}, + type_name="standard", + volume_type="default_share_type", + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.file_shares.with_raw_response.create( + project_id=1, + region_id=1, + name="test-share-file-system", + network={"network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8"}, + protocol="NFS", + size=5, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = await response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.file_shares.with_streaming_response.create( + project_id=1, + region_id=1, + name="test-share-file-system", + network={"network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8"}, + protocol="NFS", + size=5, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = await response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_2(self, async_client: AsyncGcore) -> None: + file_share = await async_client.cloud.file_shares.create( + project_id=1, + region_id=1, + name="test-share-file-system", + protocol="NFS", + size=5, + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_2(self, async_client: AsyncGcore) -> None: + file_share = await async_client.cloud.file_shares.create( + project_id=1, + region_id=1, + name="test-share-file-system", + protocol="NFS", + size=5, + share_settings={ + "allowed_characters": "LCD", + "path_length": "LCD", + "root_squash": True, + }, + tags={"my-tag": "my-tag-value"}, + type_name="vast", + volume_type="vast_share_type", + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.file_shares.with_raw_response.create( + project_id=1, + region_id=1, + name="test-share-file-system", + protocol="NFS", + size=5, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = await response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.file_shares.with_streaming_response.create( + project_id=1, + region_id=1, + name="test-share-file-system", + protocol="NFS", + size=5, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = await response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + file_share = await async_client.cloud.file_shares.update( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + file_share = await async_client.cloud.file_shares.update( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + name="some_name", + share_settings={ + "allowed_characters": "LCD", + "path_length": "LCD", + "root_squash": True, + }, + tags={}, + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.file_shares.with_raw_response.update( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = await response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.file_shares.with_streaming_response.update( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = await response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + await async_client.cloud.file_shares.with_raw_response.update( + file_share_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + file_share = await async_client.cloud.file_shares.list( + project_id=1, + region_id=1, + ) + assert_matches_type(AsyncOffsetPage[FileShare], file_share, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + file_share = await async_client.cloud.file_shares.list( + project_id=1, + region_id=1, + limit=1000, + name="test-sfs", + offset=0, + type_name="standard", + ) + assert_matches_type(AsyncOffsetPage[FileShare], file_share, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.file_shares.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = await response.parse() + assert_matches_type(AsyncOffsetPage[FileShare], file_share, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.file_shares.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = await response.parse() + assert_matches_type(AsyncOffsetPage[FileShare], file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + file_share = await async_client.cloud.file_shares.delete( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.file_shares.with_raw_response.delete( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = await response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.file_shares.with_streaming_response.delete( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = await response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + await async_client.cloud.file_shares.with_raw_response.delete( + file_share_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + file_share = await async_client.cloud.file_shares.get( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + assert_matches_type(FileShare, file_share, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.file_shares.with_raw_response.get( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = await response.parse() + assert_matches_type(FileShare, file_share, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.file_shares.with_streaming_response.get( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = await response.parse() + assert_matches_type(FileShare, file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + await async_client.cloud.file_shares.with_raw_response.get( + file_share_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_resize(self, async_client: AsyncGcore) -> None: + file_share = await async_client.cloud.file_shares.resize( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + size=5, + ) + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + async def test_raw_response_resize(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.file_shares.with_raw_response.resize( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + size=5, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_share = await response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + @parametrize + async def test_streaming_response_resize(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.file_shares.with_streaming_response.resize( + file_share_id="bd8c47ee-e565-4e26-8840-b537e6827b08", + project_id=1, + region_id=1, + size=5, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_share = await response.parse() + assert_matches_type(TaskIDList, file_share, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_resize(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_share_id` but received ''"): + await async_client.cloud.file_shares.with_raw_response.resize( + file_share_id="", + project_id=1, + region_id=1, + size=5, + ) diff --git a/tests/api_resources/cloud/test_floating_ips.py b/tests/api_resources/cloud/test_floating_ips.py new file mode 100644 index 00000000..fda155b2 --- /dev/null +++ b/tests/api_resources/cloud/test_floating_ips.py @@ -0,0 +1,753 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import ( + FloatingIP, + TaskIDList, + FloatingIPDetailed, +) + +# pyright: reportDeprecated=false + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFloatingIPs: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + floating_ip = client.cloud.floating_ips.create( + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + floating_ip = client.cloud.floating_ips.create( + project_id=1, + region_id=1, + fixed_ip_address="192.168.10.15", + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.floating_ips.with_raw_response.create( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = response.parse() + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.floating_ips.with_streaming_response.create( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = response.parse() + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + floating_ip = client.cloud.floating_ips.update( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + floating_ip = client.cloud.floating_ips.update( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + fixed_ip_address="192.168.10.15", + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + tags={}, + ) + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.floating_ips.with_raw_response.update( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = response.parse() + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.floating_ips.with_streaming_response.update( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = response.parse() + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `floating_ip_id` but received ''"): + client.cloud.floating_ips.with_raw_response.update( + floating_ip_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + floating_ip = client.cloud.floating_ips.list( + project_id=1, + region_id=1, + ) + assert_matches_type(SyncOffsetPage[FloatingIPDetailed], floating_ip, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + floating_ip = client.cloud.floating_ips.list( + project_id=1, + region_id=1, + limit=1000, + offset=0, + status="ACTIVE", + tag_key=["key1", "key2"], + tag_key_value="tag_key_value", + ) + assert_matches_type(SyncOffsetPage[FloatingIPDetailed], floating_ip, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.floating_ips.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = response.parse() + assert_matches_type(SyncOffsetPage[FloatingIPDetailed], floating_ip, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.floating_ips.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = response.parse() + assert_matches_type(SyncOffsetPage[FloatingIPDetailed], floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + floating_ip = client.cloud.floating_ips.delete( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.floating_ips.with_raw_response.delete( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = response.parse() + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.floating_ips.with_streaming_response.delete( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = response.parse() + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `floating_ip_id` but received ''"): + client.cloud.floating_ips.with_raw_response.delete( + floating_ip_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_assign(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + floating_ip = client.cloud.floating_ips.assign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) + + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + def test_method_assign_with_all_params(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + floating_ip = client.cloud.floating_ips.assign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + fixed_ip_address="192.168.10.15", + ) + + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + def test_raw_response_assign(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + response = client.cloud.floating_ips.with_raw_response.assign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = response.parse() + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + def test_streaming_response_assign(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with client.cloud.floating_ips.with_streaming_response.assign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = response.parse() + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_assign(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `floating_ip_id` but received ''"): + client.cloud.floating_ips.with_raw_response.assign( + floating_ip_id="", + project_id=1, + region_id=1, + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + floating_ip = client.cloud.floating_ips.get( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.floating_ips.with_raw_response.get( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = response.parse() + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.floating_ips.with_streaming_response.get( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = response.parse() + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `floating_ip_id` but received ''"): + client.cloud.floating_ips.with_raw_response.get( + floating_ip_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_unassign(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + floating_ip = client.cloud.floating_ips.unassign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + def test_raw_response_unassign(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + response = client.cloud.floating_ips.with_raw_response.unassign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = response.parse() + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + def test_streaming_response_unassign(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with client.cloud.floating_ips.with_streaming_response.unassign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = response.parse() + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_unassign(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `floating_ip_id` but received ''"): + client.cloud.floating_ips.with_raw_response.unassign( + floating_ip_id="", + project_id=1, + region_id=1, + ) + + +class TestAsyncFloatingIPs: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + floating_ip = await async_client.cloud.floating_ips.create( + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + floating_ip = await async_client.cloud.floating_ips.create( + project_id=1, + region_id=1, + fixed_ip_address="192.168.10.15", + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.floating_ips.with_raw_response.create( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = await response.parse() + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.floating_ips.with_streaming_response.create( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = await response.parse() + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + floating_ip = await async_client.cloud.floating_ips.update( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + floating_ip = await async_client.cloud.floating_ips.update( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + fixed_ip_address="192.168.10.15", + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + tags={}, + ) + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.floating_ips.with_raw_response.update( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = await response.parse() + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.floating_ips.with_streaming_response.update( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = await response.parse() + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `floating_ip_id` but received ''"): + await async_client.cloud.floating_ips.with_raw_response.update( + floating_ip_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + floating_ip = await async_client.cloud.floating_ips.list( + project_id=1, + region_id=1, + ) + assert_matches_type(AsyncOffsetPage[FloatingIPDetailed], floating_ip, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + floating_ip = await async_client.cloud.floating_ips.list( + project_id=1, + region_id=1, + limit=1000, + offset=0, + status="ACTIVE", + tag_key=["key1", "key2"], + tag_key_value="tag_key_value", + ) + assert_matches_type(AsyncOffsetPage[FloatingIPDetailed], floating_ip, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.floating_ips.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = await response.parse() + assert_matches_type(AsyncOffsetPage[FloatingIPDetailed], floating_ip, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.floating_ips.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = await response.parse() + assert_matches_type(AsyncOffsetPage[FloatingIPDetailed], floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + floating_ip = await async_client.cloud.floating_ips.delete( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.floating_ips.with_raw_response.delete( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = await response.parse() + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.floating_ips.with_streaming_response.delete( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = await response.parse() + assert_matches_type(TaskIDList, floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `floating_ip_id` but received ''"): + await async_client.cloud.floating_ips.with_raw_response.delete( + floating_ip_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_assign(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + floating_ip = await async_client.cloud.floating_ips.assign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) + + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + async def test_method_assign_with_all_params(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + floating_ip = await async_client.cloud.floating_ips.assign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + fixed_ip_address="192.168.10.15", + ) + + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + async def test_raw_response_assign(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + response = await async_client.cloud.floating_ips.with_raw_response.assign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = await response.parse() + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + async def test_streaming_response_assign(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + async with async_client.cloud.floating_ips.with_streaming_response.assign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = await response.parse() + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_assign(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `floating_ip_id` but received ''"): + await async_client.cloud.floating_ips.with_raw_response.assign( + floating_ip_id="", + project_id=1, + region_id=1, + port_id="ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + floating_ip = await async_client.cloud.floating_ips.get( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.floating_ips.with_raw_response.get( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = await response.parse() + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.floating_ips.with_streaming_response.get( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = await response.parse() + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `floating_ip_id` but received ''"): + await async_client.cloud.floating_ips.with_raw_response.get( + floating_ip_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_unassign(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + floating_ip = await async_client.cloud.floating_ips.unassign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + async def test_raw_response_unassign(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + response = await async_client.cloud.floating_ips.with_raw_response.unassign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + floating_ip = await response.parse() + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + @parametrize + async def test_streaming_response_unassign(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + async with async_client.cloud.floating_ips.with_streaming_response.unassign( + floating_ip_id="c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + floating_ip = await response.parse() + assert_matches_type(FloatingIP, floating_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_unassign(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `floating_ip_id` but received ''"): + await async_client.cloud.floating_ips.with_raw_response.unassign( + floating_ip_id="", + project_id=1, + region_id=1, + ) diff --git a/tests/api_resources/cloud/test_inference.py b/tests/api_resources/cloud/test_inference.py new file mode 100644 index 00000000..e9ab9978 --- /dev/null +++ b/tests/api_resources/cloud/test_inference.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import InferenceRegionCapacityList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestInference: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_capacity_by_region(self, client: Gcore) -> None: + inference = client.cloud.inference.get_capacity_by_region() + assert_matches_type(InferenceRegionCapacityList, inference, path=["response"]) + + @parametrize + def test_raw_response_get_capacity_by_region(self, client: Gcore) -> None: + response = client.cloud.inference.with_raw_response.get_capacity_by_region() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + inference = response.parse() + assert_matches_type(InferenceRegionCapacityList, inference, path=["response"]) + + @parametrize + def test_streaming_response_get_capacity_by_region(self, client: Gcore) -> None: + with client.cloud.inference.with_streaming_response.get_capacity_by_region() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + inference = response.parse() + assert_matches_type(InferenceRegionCapacityList, inference, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncInference: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_capacity_by_region(self, async_client: AsyncGcore) -> None: + inference = await async_client.cloud.inference.get_capacity_by_region() + assert_matches_type(InferenceRegionCapacityList, inference, path=["response"]) + + @parametrize + async def test_raw_response_get_capacity_by_region(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.with_raw_response.get_capacity_by_region() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + inference = await response.parse() + assert_matches_type(InferenceRegionCapacityList, inference, path=["response"]) + + @parametrize + async def test_streaming_response_get_capacity_by_region(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.with_streaming_response.get_capacity_by_region() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + inference = await response.parse() + assert_matches_type(InferenceRegionCapacityList, inference, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/test_instances.py b/tests/api_resources/cloud/test_instances.py new file mode 100644 index 00000000..d5c24486 --- /dev/null +++ b/tests/api_resources/cloud/test_instances.py @@ -0,0 +1,1759 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import ( + Console, + Instance, + TaskIDList, + InstanceInterface, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestInstances: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + instance = client.cloud.instances.create( + project_id=1, + region_id=1, + flavor="g2-standard-32-64", + interfaces=[{"type": "external"}], + volumes=[ + { + "size": 20, + "source": "new-volume", + } + ], + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + instance = client.cloud.instances.create( + project_id=1, + region_id=1, + flavor="g2-standard-32-64", + interfaces=[ + { + "type": "external", + "interface_name": "eth0", + "ip_family": "ipv4", + "security_groups": [{"id": "ae74714c-c380-48b4-87f8-758d656cdad6"}], + } + ], + volumes=[ + { + "size": 20, + "source": "new-volume", + "attachment_tag": "boot", + "delete_on_termination": False, + "name": "boot-volume", + "tags": {"my-tag": "my-tag-value"}, + "type_name": "ssd_hiiops", + } + ], + allow_app_ports=True, + configuration={"foo": "bar"}, + name="my-instance", + name_template="name_template", + password="password", + security_groups=[{"id": "ae74714c-c380-48b4-87f8-758d656cdad6"}], + servergroup_id="servergroup_id", + ssh_key_name="my-ssh-key", + tags={"my-tag": "my-tag-value"}, + user_data="user_data", + username="username", + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.create( + project_id=1, + region_id=1, + flavor="g2-standard-32-64", + interfaces=[{"type": "external"}], + volumes=[ + { + "size": 20, + "source": "new-volume", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.create( + project_id=1, + region_id=1, + flavor="g2-standard-32-64", + interfaces=[{"type": "external"}], + volumes=[ + { + "size": 20, + "source": "new-volume", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + instance = client.cloud.instances.update( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Instance, instance, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + instance = client.cloud.instances.update( + instance_id="instance_id", + project_id=0, + region_id=0, + name="instance_name", + tags={}, + ) + assert_matches_type(Instance, instance, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.update( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert_matches_type(Instance, instance, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.update( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert_matches_type(Instance, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.with_raw_response.update( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + instance = client.cloud.instances.list( + project_id=1, + region_id=1, + ) + assert_matches_type(SyncOffsetPage[Instance], instance, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + instance = client.cloud.instances.list( + project_id=1, + region_id=1, + available_floating=True, + changes_before=parse_datetime("2025-10-01T12:00:00Z"), + changes_since=parse_datetime("2025-10-01T12:00:00Z"), + exclude_flavor_prefix="g1-", + exclude_secgroup="secgroup_name", + flavor_id="g2-standard-32-64", + flavor_prefix="g2-", + include_ai=False, + include_baremetal=False, + include_k8s=True, + ip="192.168.0.1", + limit=1000, + name="name", + offset=0, + only_isolated=True, + only_with_fixed_external_ip=True, + order_by="name.asc", + profile_name="profile_name", + protection_status="Active", + status="ACTIVE", + tag_key_value="tag_key_value", + tag_value=["value1", "value2"], + type_ddos_profile="advanced", + uuid="b5b4d65d-945f-4b98-ab6f-332319c724ef", + with_ddos=True, + with_interfaces_name=True, + ) + assert_matches_type(SyncOffsetPage[Instance], instance, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert_matches_type(SyncOffsetPage[Instance], instance, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert_matches_type(SyncOffsetPage[Instance], instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + instance = client.cloud.instances.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_method_delete_with_all_params(self, client: Gcore) -> None: + instance = client.cloud.instances.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + delete_floatings=True, + floatings="floatings", + reserved_fixed_ips="reserved_fixed_ips", + volumes="volume_id_1,volume_id_2", + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.with_raw_response.delete( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_action_overload_1(self, client: Gcore) -> None: + instance = client.cloud.instances.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="start", + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_method_action_with_all_params_overload_1(self, client: Gcore) -> None: + instance = client.cloud.instances.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="start", + activate_profile=True, + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_raw_response_action_overload_1(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="start", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_streaming_response_action_overload_1(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="start", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_action_overload_1(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.with_raw_response.action( + instance_id="", + project_id=0, + region_id=0, + action="start", + ) + + @parametrize + def test_method_action_overload_2(self, client: Gcore) -> None: + instance = client.cloud.instances.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="stop", + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_raw_response_action_overload_2(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="stop", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_streaming_response_action_overload_2(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="stop", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_action_overload_2(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.with_raw_response.action( + instance_id="", + project_id=0, + region_id=0, + action="stop", + ) + + @parametrize + def test_method_add_to_placement_group(self, client: Gcore) -> None: + instance = client.cloud.instances.add_to_placement_group( + instance_id="instance_id", + project_id=0, + region_id=0, + servergroup_id="47003067-550a-6f17-93b6-81ee16ba061e", + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_raw_response_add_to_placement_group(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.add_to_placement_group( + instance_id="instance_id", + project_id=0, + region_id=0, + servergroup_id="47003067-550a-6f17-93b6-81ee16ba061e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_streaming_response_add_to_placement_group(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.add_to_placement_group( + instance_id="instance_id", + project_id=0, + region_id=0, + servergroup_id="47003067-550a-6f17-93b6-81ee16ba061e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_add_to_placement_group(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.with_raw_response.add_to_placement_group( + instance_id="", + project_id=0, + region_id=0, + servergroup_id="47003067-550a-6f17-93b6-81ee16ba061e", + ) + + @parametrize + def test_method_assign_security_group(self, client: Gcore) -> None: + instance = client.cloud.instances.assign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert instance is None + + @parametrize + def test_method_assign_security_group_with_all_params(self, client: Gcore) -> None: + instance = client.cloud.instances.assign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + name="some_name", + ports_security_group_names=[ + { + "port_id": None, + "security_group_names": ["some_name"], + }, + { + "port_id": "ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + "security_group_names": ["name1", "name2"], + }, + ], + ) + assert instance is None + + @parametrize + def test_raw_response_assign_security_group(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.assign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert instance is None + + @parametrize + def test_streaming_response_assign_security_group(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.assign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert instance is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_assign_security_group(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.with_raw_response.assign_security_group( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_disable_port_security(self, client: Gcore) -> None: + instance = client.cloud.instances.disable_port_security( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(InstanceInterface, instance, path=["response"]) + + @parametrize + def test_raw_response_disable_port_security(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.disable_port_security( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert_matches_type(InstanceInterface, instance, path=["response"]) + + @parametrize + def test_streaming_response_disable_port_security(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.disable_port_security( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert_matches_type(InstanceInterface, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_disable_port_security(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + client.cloud.instances.with_raw_response.disable_port_security( + port_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_enable_port_security(self, client: Gcore) -> None: + instance = client.cloud.instances.enable_port_security( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(InstanceInterface, instance, path=["response"]) + + @parametrize + def test_raw_response_enable_port_security(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.enable_port_security( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert_matches_type(InstanceInterface, instance, path=["response"]) + + @parametrize + def test_streaming_response_enable_port_security(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.enable_port_security( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert_matches_type(InstanceInterface, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_enable_port_security(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + client.cloud.instances.with_raw_response.enable_port_security( + port_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + instance = client.cloud.instances.get( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Instance, instance, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.get( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert_matches_type(Instance, instance, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.get( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert_matches_type(Instance, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.with_raw_response.get( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_get_console(self, client: Gcore) -> None: + instance = client.cloud.instances.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Console, instance, path=["response"]) + + @parametrize + def test_method_get_console_with_all_params(self, client: Gcore) -> None: + instance = client.cloud.instances.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + console_type="console_type", + ) + assert_matches_type(Console, instance, path=["response"]) + + @parametrize + def test_raw_response_get_console(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert_matches_type(Console, instance, path=["response"]) + + @parametrize + def test_streaming_response_get_console(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert_matches_type(Console, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_console(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.with_raw_response.get_console( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_remove_from_placement_group(self, client: Gcore) -> None: + instance = client.cloud.instances.remove_from_placement_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_raw_response_remove_from_placement_group(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.remove_from_placement_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_streaming_response_remove_from_placement_group(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.remove_from_placement_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_remove_from_placement_group(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.with_raw_response.remove_from_placement_group( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_resize(self, client: Gcore) -> None: + instance = client.cloud.instances.resize( + instance_id="instance_id", + project_id=0, + region_id=0, + flavor_id="g1s-shared-1-0.5", + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_raw_response_resize(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.resize( + instance_id="instance_id", + project_id=0, + region_id=0, + flavor_id="g1s-shared-1-0.5", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + def test_streaming_response_resize(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.resize( + instance_id="instance_id", + project_id=0, + region_id=0, + flavor_id="g1s-shared-1-0.5", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_resize(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.with_raw_response.resize( + instance_id="", + project_id=0, + region_id=0, + flavor_id="g1s-shared-1-0.5", + ) + + @parametrize + def test_method_unassign_security_group(self, client: Gcore) -> None: + instance = client.cloud.instances.unassign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert instance is None + + @parametrize + def test_method_unassign_security_group_with_all_params(self, client: Gcore) -> None: + instance = client.cloud.instances.unassign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + name="some_name", + ports_security_group_names=[ + { + "port_id": None, + "security_group_names": ["some_name"], + }, + { + "port_id": "ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + "security_group_names": ["name1", "name2"], + }, + ], + ) + assert instance is None + + @parametrize + def test_raw_response_unassign_security_group(self, client: Gcore) -> None: + response = client.cloud.instances.with_raw_response.unassign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = response.parse() + assert instance is None + + @parametrize + def test_streaming_response_unassign_security_group(self, client: Gcore) -> None: + with client.cloud.instances.with_streaming_response.unassign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = response.parse() + assert instance is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_unassign_security_group(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + client.cloud.instances.with_raw_response.unassign_security_group( + instance_id="", + project_id=0, + region_id=0, + ) + + +class TestAsyncInstances: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.create( + project_id=1, + region_id=1, + flavor="g2-standard-32-64", + interfaces=[{"type": "external"}], + volumes=[ + { + "size": 20, + "source": "new-volume", + } + ], + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.create( + project_id=1, + region_id=1, + flavor="g2-standard-32-64", + interfaces=[ + { + "type": "external", + "interface_name": "eth0", + "ip_family": "ipv4", + "security_groups": [{"id": "ae74714c-c380-48b4-87f8-758d656cdad6"}], + } + ], + volumes=[ + { + "size": 20, + "source": "new-volume", + "attachment_tag": "boot", + "delete_on_termination": False, + "name": "boot-volume", + "tags": {"my-tag": "my-tag-value"}, + "type_name": "ssd_hiiops", + } + ], + allow_app_ports=True, + configuration={"foo": "bar"}, + name="my-instance", + name_template="name_template", + password="password", + security_groups=[{"id": "ae74714c-c380-48b4-87f8-758d656cdad6"}], + servergroup_id="servergroup_id", + ssh_key_name="my-ssh-key", + tags={"my-tag": "my-tag-value"}, + user_data="user_data", + username="username", + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.create( + project_id=1, + region_id=1, + flavor="g2-standard-32-64", + interfaces=[{"type": "external"}], + volumes=[ + { + "size": 20, + "source": "new-volume", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.create( + project_id=1, + region_id=1, + flavor="g2-standard-32-64", + interfaces=[{"type": "external"}], + volumes=[ + { + "size": 20, + "source": "new-volume", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.update( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Instance, instance, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.update( + instance_id="instance_id", + project_id=0, + region_id=0, + name="instance_name", + tags={}, + ) + assert_matches_type(Instance, instance, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.update( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert_matches_type(Instance, instance, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.update( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert_matches_type(Instance, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.with_raw_response.update( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.list( + project_id=1, + region_id=1, + ) + assert_matches_type(AsyncOffsetPage[Instance], instance, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.list( + project_id=1, + region_id=1, + available_floating=True, + changes_before=parse_datetime("2025-10-01T12:00:00Z"), + changes_since=parse_datetime("2025-10-01T12:00:00Z"), + exclude_flavor_prefix="g1-", + exclude_secgroup="secgroup_name", + flavor_id="g2-standard-32-64", + flavor_prefix="g2-", + include_ai=False, + include_baremetal=False, + include_k8s=True, + ip="192.168.0.1", + limit=1000, + name="name", + offset=0, + only_isolated=True, + only_with_fixed_external_ip=True, + order_by="name.asc", + profile_name="profile_name", + protection_status="Active", + status="ACTIVE", + tag_key_value="tag_key_value", + tag_value=["value1", "value2"], + type_ddos_profile="advanced", + uuid="b5b4d65d-945f-4b98-ab6f-332319c724ef", + with_ddos=True, + with_interfaces_name=True, + ) + assert_matches_type(AsyncOffsetPage[Instance], instance, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert_matches_type(AsyncOffsetPage[Instance], instance, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert_matches_type(AsyncOffsetPage[Instance], instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + delete_floatings=True, + floatings="floatings", + reserved_fixed_ips="reserved_fixed_ips", + volumes="volume_id_1,volume_id_2", + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.with_raw_response.delete( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_action_overload_1(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="start", + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_method_action_with_all_params_overload_1(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="start", + activate_profile=True, + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_raw_response_action_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="start", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_streaming_response_action_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="start", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_action_overload_1(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.with_raw_response.action( + instance_id="", + project_id=0, + region_id=0, + action="start", + ) + + @parametrize + async def test_method_action_overload_2(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="stop", + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_raw_response_action_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="stop", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_streaming_response_action_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.action( + instance_id="instance_id", + project_id=0, + region_id=0, + action="stop", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_action_overload_2(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.with_raw_response.action( + instance_id="", + project_id=0, + region_id=0, + action="stop", + ) + + @parametrize + async def test_method_add_to_placement_group(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.add_to_placement_group( + instance_id="instance_id", + project_id=0, + region_id=0, + servergroup_id="47003067-550a-6f17-93b6-81ee16ba061e", + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_raw_response_add_to_placement_group(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.add_to_placement_group( + instance_id="instance_id", + project_id=0, + region_id=0, + servergroup_id="47003067-550a-6f17-93b6-81ee16ba061e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_streaming_response_add_to_placement_group(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.add_to_placement_group( + instance_id="instance_id", + project_id=0, + region_id=0, + servergroup_id="47003067-550a-6f17-93b6-81ee16ba061e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_add_to_placement_group(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.with_raw_response.add_to_placement_group( + instance_id="", + project_id=0, + region_id=0, + servergroup_id="47003067-550a-6f17-93b6-81ee16ba061e", + ) + + @parametrize + async def test_method_assign_security_group(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.assign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert instance is None + + @parametrize + async def test_method_assign_security_group_with_all_params(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.assign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + name="some_name", + ports_security_group_names=[ + { + "port_id": None, + "security_group_names": ["some_name"], + }, + { + "port_id": "ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + "security_group_names": ["name1", "name2"], + }, + ], + ) + assert instance is None + + @parametrize + async def test_raw_response_assign_security_group(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.assign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert instance is None + + @parametrize + async def test_streaming_response_assign_security_group(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.assign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert instance is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_assign_security_group(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.with_raw_response.assign_security_group( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_disable_port_security(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.disable_port_security( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(InstanceInterface, instance, path=["response"]) + + @parametrize + async def test_raw_response_disable_port_security(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.disable_port_security( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert_matches_type(InstanceInterface, instance, path=["response"]) + + @parametrize + async def test_streaming_response_disable_port_security(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.disable_port_security( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert_matches_type(InstanceInterface, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_disable_port_security(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + await async_client.cloud.instances.with_raw_response.disable_port_security( + port_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_enable_port_security(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.enable_port_security( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(InstanceInterface, instance, path=["response"]) + + @parametrize + async def test_raw_response_enable_port_security(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.enable_port_security( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert_matches_type(InstanceInterface, instance, path=["response"]) + + @parametrize + async def test_streaming_response_enable_port_security(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.enable_port_security( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert_matches_type(InstanceInterface, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_enable_port_security(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + await async_client.cloud.instances.with_raw_response.enable_port_security( + port_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.get( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Instance, instance, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.get( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert_matches_type(Instance, instance, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.get( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert_matches_type(Instance, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.with_raw_response.get( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_get_console(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(Console, instance, path=["response"]) + + @parametrize + async def test_method_get_console_with_all_params(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + console_type="console_type", + ) + assert_matches_type(Console, instance, path=["response"]) + + @parametrize + async def test_raw_response_get_console(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert_matches_type(Console, instance, path=["response"]) + + @parametrize + async def test_streaming_response_get_console(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.get_console( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert_matches_type(Console, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_console(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.with_raw_response.get_console( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_remove_from_placement_group(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.remove_from_placement_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_raw_response_remove_from_placement_group(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.remove_from_placement_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_streaming_response_remove_from_placement_group(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.remove_from_placement_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_remove_from_placement_group(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.with_raw_response.remove_from_placement_group( + instance_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_resize(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.resize( + instance_id="instance_id", + project_id=0, + region_id=0, + flavor_id="g1s-shared-1-0.5", + ) + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_raw_response_resize(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.resize( + instance_id="instance_id", + project_id=0, + region_id=0, + flavor_id="g1s-shared-1-0.5", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + @parametrize + async def test_streaming_response_resize(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.resize( + instance_id="instance_id", + project_id=0, + region_id=0, + flavor_id="g1s-shared-1-0.5", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert_matches_type(TaskIDList, instance, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_resize(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.with_raw_response.resize( + instance_id="", + project_id=0, + region_id=0, + flavor_id="g1s-shared-1-0.5", + ) + + @parametrize + async def test_method_unassign_security_group(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.unassign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + assert instance is None + + @parametrize + async def test_method_unassign_security_group_with_all_params(self, async_client: AsyncGcore) -> None: + instance = await async_client.cloud.instances.unassign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + name="some_name", + ports_security_group_names=[ + { + "port_id": None, + "security_group_names": ["some_name"], + }, + { + "port_id": "ee2402d0-f0cd-4503-9b75-69be1d11c5f1", + "security_group_names": ["name1", "name2"], + }, + ], + ) + assert instance is None + + @parametrize + async def test_raw_response_unassign_security_group(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.instances.with_raw_response.unassign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + instance = await response.parse() + assert instance is None + + @parametrize + async def test_streaming_response_unassign_security_group(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.instances.with_streaming_response.unassign_security_group( + instance_id="instance_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + instance = await response.parse() + assert instance is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_unassign_security_group(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `instance_id` but received ''"): + await async_client.cloud.instances.with_raw_response.unassign_security_group( + instance_id="", + project_id=0, + region_id=0, + ) diff --git a/tests/api_resources/cloud/test_ip_ranges.py b/tests/api_resources/cloud/test_ip_ranges.py new file mode 100644 index 00000000..e7dde3b1 --- /dev/null +++ b/tests/api_resources/cloud/test_ip_ranges.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import IPRanges + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestIPRanges: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + ip_range = client.cloud.ip_ranges.list() + assert_matches_type(IPRanges, ip_range, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.ip_ranges.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_range = response.parse() + assert_matches_type(IPRanges, ip_range, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.ip_ranges.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_range = response.parse() + assert_matches_type(IPRanges, ip_range, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncIPRanges: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + ip_range = await async_client.cloud.ip_ranges.list() + assert_matches_type(IPRanges, ip_range, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.ip_ranges.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_range = await response.parse() + assert_matches_type(IPRanges, ip_range, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.ip_ranges.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_range = await response.parse() + assert_matches_type(IPRanges, ip_range, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/test_k8s.py b/tests/api_resources/cloud/test_k8s.py new file mode 100644 index 00000000..43c912f3 --- /dev/null +++ b/tests/api_resources/cloud/test_k8s.py @@ -0,0 +1,92 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import K8SClusterVersionList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestK8S: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list_versions(self, client: Gcore) -> None: + k8s = client.cloud.k8s.list_versions( + project_id=1, + region_id=7, + ) + assert_matches_type(K8SClusterVersionList, k8s, path=["response"]) + + @parametrize + def test_raw_response_list_versions(self, client: Gcore) -> None: + response = client.cloud.k8s.with_raw_response.list_versions( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + k8s = response.parse() + assert_matches_type(K8SClusterVersionList, k8s, path=["response"]) + + @parametrize + def test_streaming_response_list_versions(self, client: Gcore) -> None: + with client.cloud.k8s.with_streaming_response.list_versions( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + k8s = response.parse() + assert_matches_type(K8SClusterVersionList, k8s, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncK8S: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list_versions(self, async_client: AsyncGcore) -> None: + k8s = await async_client.cloud.k8s.list_versions( + project_id=1, + region_id=7, + ) + assert_matches_type(K8SClusterVersionList, k8s, path=["response"]) + + @parametrize + async def test_raw_response_list_versions(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.k8s.with_raw_response.list_versions( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + k8s = await response.parse() + assert_matches_type(K8SClusterVersionList, k8s, path=["response"]) + + @parametrize + async def test_streaming_response_list_versions(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.k8s.with_streaming_response.list_versions( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + k8s = await response.parse() + assert_matches_type(K8SClusterVersionList, k8s, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/test_load_balancers.py b/tests/api_resources/cloud/test_load_balancers.py new file mode 100644 index 00000000..75c7a421 --- /dev/null +++ b/tests/api_resources/cloud/test_load_balancers.py @@ -0,0 +1,966 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import ( + TaskIDList, + LoadBalancer, +) + +# pyright: reportDeprecated=false + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestLoadBalancers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + load_balancer = client.cloud.load_balancers.create( + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + load_balancer = client.cloud.load_balancers.create( + project_id=1, + region_id=7, + flavor="lb1-1-2", + floating_ip={ + "existing_floating_id": "c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + "source": "existing", + }, + listeners=[ + { + "name": "my_listener", + "protocol": "HTTP", + "protocol_port": 80, + "allowed_cidrs": ["10.0.0.0/8"], + "connection_limit": 100000, + "insert_x_forwarded": False, + "pools": [ + { + "lb_algorithm": "LEAST_CONNECTIONS", + "name": "pool_name", + "protocol": "HTTP", + "ca_secret_id": "ca_secret_id", + "crl_secret_id": "crl_secret_id", + "healthmonitor": { + "delay": 10, + "max_retries": 3, + "timeout": 5, + "type": "HTTP", + "admin_state_up": True, + "expected_codes": "200,301,302", + "http_method": "GET", + "max_retries_down": 3, + "url_path": "/", + }, + "members": [ + { + "address": "192.168.1.101", + "protocol_port": 8000, + "admin_state_up": True, + "backup": True, + "instance_id": "a7e7e8d6-0bf7-4ac9-8170-831b47ee2ba9", + "monitor_address": "monitor_address", + "monitor_port": 1, + "subnet_id": "32283b0b-b560-4690-810c-f672cbb2e28d", + "weight": 2, + }, + { + "address": "192.168.1.102", + "protocol_port": 8000, + "admin_state_up": True, + "backup": True, + "instance_id": "169942e0-9b53-42df-95ef-1a8b6525c2bd", + "monitor_address": "monitor_address", + "monitor_port": 1, + "subnet_id": "32283b0b-b560-4690-810c-f672cbb2e28d", + "weight": 4, + }, + ], + "secret_id": "secret_id", + "session_persistence": { + "type": "APP_COOKIE", + "cookie_name": "cookie_name", + "persistence_granularity": "persistence_granularity", + "persistence_timeout": 0, + }, + "timeout_client_data": 50000, + "timeout_member_connect": 50000, + "timeout_member_data": 0, + } + ], + "secret_id": "", + "sni_secret_id": ["f2e734d0-fa2b-42c2-ad33-4c6db5101e00", "eb121225-7ded-4ff3-ae1f-599e145dd7cb"], + "timeout_client_data": 50000, + "timeout_member_connect": 50000, + "timeout_member_data": None, + "user_list": [ + { + "encrypted_password": "$5$isRr.HJ1IrQP38.m$oViu3DJOpUG2ZsjCBtbITV3mqpxxbZfyWJojLPNSPO5", + "username": "admin", + } + ], + } + ], + logging={ + "destination_region_id": 1, + "enabled": True, + "retention_policy": {"period": 45}, + "topic_name": "my-log-name", + }, + name="new_load_balancer", + name_template="lb_name_template", + preferred_connectivity="L2", + tags={"my-tag": "my-tag-value"}, + vip_ip_family="dual", + vip_network_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + vip_port_id="ff83e13a-b256-4be2-ba5d-028d3f0ab450", + vip_subnet_id="4e7802d3-5023-44b8-b298-7726558fddf4", + ) + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.load_balancers.with_raw_response.create( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.load_balancers.with_streaming_response.create( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + load_balancer = client.cloud.load_balancers.update( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + load_balancer = client.cloud.load_balancers.update( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + logging={ + "destination_region_id": 1, + "enabled": True, + "retention_policy": {"period": 45}, + "topic_name": "my-log-name", + }, + name="some_name", + preferred_connectivity="L2", + tags={}, + ) + + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + response = client.cloud.load_balancers.with_raw_response.update( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = response.parse() + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with client.cloud.load_balancers.with_streaming_response.update( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = response.parse() + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + client.cloud.load_balancers.with_raw_response.update( + load_balancer_id="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + load_balancer = client.cloud.load_balancers.list( + project_id=1, + region_id=7, + ) + assert_matches_type(SyncOffsetPage[LoadBalancer], load_balancer, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + load_balancer = client.cloud.load_balancers.list( + project_id=1, + region_id=7, + assigned_floating=True, + limit=1000, + logging_enabled=True, + name="lb_name", + offset=0, + order_by="name.asc", + show_stats=True, + tag_key=["key1", "key2"], + tag_key_value="tag_key_value", + with_ddos=True, + ) + assert_matches_type(SyncOffsetPage[LoadBalancer], load_balancer, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.load_balancers.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = response.parse() + assert_matches_type(SyncOffsetPage[LoadBalancer], load_balancer, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.load_balancers.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = response.parse() + assert_matches_type(SyncOffsetPage[LoadBalancer], load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + load_balancer = client.cloud.load_balancers.delete( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.load_balancers.with_raw_response.delete( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.load_balancers.with_streaming_response.delete( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + client.cloud.load_balancers.with_raw_response.delete( + load_balancer_id="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_failover(self, client: Gcore) -> None: + load_balancer = client.cloud.load_balancers.failover( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + def test_method_failover_with_all_params(self, client: Gcore) -> None: + load_balancer = client.cloud.load_balancers.failover( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + force=True, + ) + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + def test_raw_response_failover(self, client: Gcore) -> None: + response = client.cloud.load_balancers.with_raw_response.failover( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + def test_streaming_response_failover(self, client: Gcore) -> None: + with client.cloud.load_balancers.with_streaming_response.failover( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_failover(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + client.cloud.load_balancers.with_raw_response.failover( + load_balancer_id="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + load_balancer = client.cloud.load_balancers.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + @parametrize + def test_method_get_with_all_params(self, client: Gcore) -> None: + load_balancer = client.cloud.load_balancers.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + show_stats=True, + with_ddos=True, + ) + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.load_balancers.with_raw_response.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = response.parse() + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.load_balancers.with_streaming_response.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = response.parse() + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + client.cloud.load_balancers.with_raw_response.get( + load_balancer_id="", + project_id=1, + region_id=7, + ) + + @parametrize + def test_method_resize(self, client: Gcore) -> None: + load_balancer = client.cloud.load_balancers.resize( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + flavor="lb1-2-4", + ) + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + def test_raw_response_resize(self, client: Gcore) -> None: + response = client.cloud.load_balancers.with_raw_response.resize( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + flavor="lb1-2-4", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + def test_streaming_response_resize(self, client: Gcore) -> None: + with client.cloud.load_balancers.with_streaming_response.resize( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + flavor="lb1-2-4", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_resize(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + client.cloud.load_balancers.with_raw_response.resize( + load_balancer_id="", + project_id=1, + region_id=7, + flavor="lb1-2-4", + ) + + +class TestAsyncLoadBalancers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + load_balancer = await async_client.cloud.load_balancers.create( + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + load_balancer = await async_client.cloud.load_balancers.create( + project_id=1, + region_id=7, + flavor="lb1-1-2", + floating_ip={ + "existing_floating_id": "c64e5db1-5f1f-43ec-a8d9-5090df85b82d", + "source": "existing", + }, + listeners=[ + { + "name": "my_listener", + "protocol": "HTTP", + "protocol_port": 80, + "allowed_cidrs": ["10.0.0.0/8"], + "connection_limit": 100000, + "insert_x_forwarded": False, + "pools": [ + { + "lb_algorithm": "LEAST_CONNECTIONS", + "name": "pool_name", + "protocol": "HTTP", + "ca_secret_id": "ca_secret_id", + "crl_secret_id": "crl_secret_id", + "healthmonitor": { + "delay": 10, + "max_retries": 3, + "timeout": 5, + "type": "HTTP", + "admin_state_up": True, + "expected_codes": "200,301,302", + "http_method": "GET", + "max_retries_down": 3, + "url_path": "/", + }, + "members": [ + { + "address": "192.168.1.101", + "protocol_port": 8000, + "admin_state_up": True, + "backup": True, + "instance_id": "a7e7e8d6-0bf7-4ac9-8170-831b47ee2ba9", + "monitor_address": "monitor_address", + "monitor_port": 1, + "subnet_id": "32283b0b-b560-4690-810c-f672cbb2e28d", + "weight": 2, + }, + { + "address": "192.168.1.102", + "protocol_port": 8000, + "admin_state_up": True, + "backup": True, + "instance_id": "169942e0-9b53-42df-95ef-1a8b6525c2bd", + "monitor_address": "monitor_address", + "monitor_port": 1, + "subnet_id": "32283b0b-b560-4690-810c-f672cbb2e28d", + "weight": 4, + }, + ], + "secret_id": "secret_id", + "session_persistence": { + "type": "APP_COOKIE", + "cookie_name": "cookie_name", + "persistence_granularity": "persistence_granularity", + "persistence_timeout": 0, + }, + "timeout_client_data": 50000, + "timeout_member_connect": 50000, + "timeout_member_data": 0, + } + ], + "secret_id": "", + "sni_secret_id": ["f2e734d0-fa2b-42c2-ad33-4c6db5101e00", "eb121225-7ded-4ff3-ae1f-599e145dd7cb"], + "timeout_client_data": 50000, + "timeout_member_connect": 50000, + "timeout_member_data": None, + "user_list": [ + { + "encrypted_password": "$5$isRr.HJ1IrQP38.m$oViu3DJOpUG2ZsjCBtbITV3mqpxxbZfyWJojLPNSPO5", + "username": "admin", + } + ], + } + ], + logging={ + "destination_region_id": 1, + "enabled": True, + "retention_policy": {"period": 45}, + "topic_name": "my-log-name", + }, + name="new_load_balancer", + name_template="lb_name_template", + preferred_connectivity="L2", + tags={"my-tag": "my-tag-value"}, + vip_ip_family="dual", + vip_network_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + vip_port_id="ff83e13a-b256-4be2-ba5d-028d3f0ab450", + vip_subnet_id="4e7802d3-5023-44b8-b298-7726558fddf4", + ) + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.with_raw_response.create( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = await response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.with_streaming_response.create( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = await response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + load_balancer = await async_client.cloud.load_balancers.update( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + load_balancer = await async_client.cloud.load_balancers.update( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + logging={ + "destination_region_id": 1, + "enabled": True, + "retention_policy": {"period": 45}, + "topic_name": "my-log-name", + }, + name="some_name", + preferred_connectivity="L2", + tags={}, + ) + + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + response = await async_client.cloud.load_balancers.with_raw_response.update( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = await response.parse() + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + async with async_client.cloud.load_balancers.with_streaming_response.update( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = await response.parse() + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + await async_client.cloud.load_balancers.with_raw_response.update( + load_balancer_id="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + load_balancer = await async_client.cloud.load_balancers.list( + project_id=1, + region_id=7, + ) + assert_matches_type(AsyncOffsetPage[LoadBalancer], load_balancer, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + load_balancer = await async_client.cloud.load_balancers.list( + project_id=1, + region_id=7, + assigned_floating=True, + limit=1000, + logging_enabled=True, + name="lb_name", + offset=0, + order_by="name.asc", + show_stats=True, + tag_key=["key1", "key2"], + tag_key_value="tag_key_value", + with_ddos=True, + ) + assert_matches_type(AsyncOffsetPage[LoadBalancer], load_balancer, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.with_raw_response.list( + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = await response.parse() + assert_matches_type(AsyncOffsetPage[LoadBalancer], load_balancer, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.with_streaming_response.list( + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = await response.parse() + assert_matches_type(AsyncOffsetPage[LoadBalancer], load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + load_balancer = await async_client.cloud.load_balancers.delete( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.with_raw_response.delete( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = await response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.with_streaming_response.delete( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = await response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + await async_client.cloud.load_balancers.with_raw_response.delete( + load_balancer_id="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_failover(self, async_client: AsyncGcore) -> None: + load_balancer = await async_client.cloud.load_balancers.failover( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + async def test_method_failover_with_all_params(self, async_client: AsyncGcore) -> None: + load_balancer = await async_client.cloud.load_balancers.failover( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + force=True, + ) + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + async def test_raw_response_failover(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.with_raw_response.failover( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = await response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + async def test_streaming_response_failover(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.with_streaming_response.failover( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = await response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_failover(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + await async_client.cloud.load_balancers.with_raw_response.failover( + load_balancer_id="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + load_balancer = await async_client.cloud.load_balancers.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + @parametrize + async def test_method_get_with_all_params(self, async_client: AsyncGcore) -> None: + load_balancer = await async_client.cloud.load_balancers.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + show_stats=True, + with_ddos=True, + ) + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.with_raw_response.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = await response.parse() + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.with_streaming_response.get( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = await response.parse() + assert_matches_type(LoadBalancer, load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + await async_client.cloud.load_balancers.with_raw_response.get( + load_balancer_id="", + project_id=1, + region_id=7, + ) + + @parametrize + async def test_method_resize(self, async_client: AsyncGcore) -> None: + load_balancer = await async_client.cloud.load_balancers.resize( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + flavor="lb1-2-4", + ) + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + async def test_raw_response_resize(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.load_balancers.with_raw_response.resize( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + flavor="lb1-2-4", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + load_balancer = await response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + @parametrize + async def test_streaming_response_resize(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.load_balancers.with_streaming_response.resize( + load_balancer_id="ac307687-31a4-4a11-a949-6bea1b2878f5", + project_id=1, + region_id=7, + flavor="lb1-2-4", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + load_balancer = await response.parse() + assert_matches_type(TaskIDList, load_balancer, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_resize(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `load_balancer_id` but received ''"): + await async_client.cloud.load_balancers.with_raw_response.resize( + load_balancer_id="", + project_id=1, + region_id=7, + flavor="lb1-2-4", + ) diff --git a/tests/api_resources/cloud/test_networks.py b/tests/api_resources/cloud/test_networks.py new file mode 100644 index 00000000..273791bd --- /dev/null +++ b/tests/api_resources/cloud/test_networks.py @@ -0,0 +1,520 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import ( + Network, + TaskIDList, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestNetworks: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + network = client.cloud.networks.create( + project_id=1, + region_id=1, + name="my network", + ) + assert_matches_type(TaskIDList, network, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + network = client.cloud.networks.create( + project_id=1, + region_id=1, + name="my network", + create_router=True, + tags={"my-tag": "my-tag-value"}, + type="vxlan", + ) + assert_matches_type(TaskIDList, network, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.networks.with_raw_response.create( + project_id=1, + region_id=1, + name="my network", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network = response.parse() + assert_matches_type(TaskIDList, network, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.networks.with_streaming_response.create( + project_id=1, + region_id=1, + name="my network", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network = response.parse() + assert_matches_type(TaskIDList, network, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + network = client.cloud.networks.update( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + assert_matches_type(Network, network, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + network = client.cloud.networks.update( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + name="some_name", + tags={}, + ) + assert_matches_type(Network, network, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.networks.with_raw_response.update( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network = response.parse() + assert_matches_type(Network, network, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.networks.with_streaming_response.update( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network = response.parse() + assert_matches_type(Network, network, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `network_id` but received ''"): + client.cloud.networks.with_raw_response.update( + network_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + network = client.cloud.networks.list( + project_id=1, + region_id=1, + ) + assert_matches_type(SyncOffsetPage[Network], network, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + network = client.cloud.networks.list( + project_id=1, + region_id=1, + limit=1000, + name="my-network", + offset=0, + order_by="created_at.desc", + tag_key=["key1", "key2"], + tag_key_value="tag_key_value", + ) + assert_matches_type(SyncOffsetPage[Network], network, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.networks.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network = response.parse() + assert_matches_type(SyncOffsetPage[Network], network, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.networks.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network = response.parse() + assert_matches_type(SyncOffsetPage[Network], network, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + network = client.cloud.networks.delete( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, network, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.networks.with_raw_response.delete( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network = response.parse() + assert_matches_type(TaskIDList, network, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.networks.with_streaming_response.delete( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network = response.parse() + assert_matches_type(TaskIDList, network, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `network_id` but received ''"): + client.cloud.networks.with_raw_response.delete( + network_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + network = client.cloud.networks.get( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + assert_matches_type(Network, network, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.networks.with_raw_response.get( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network = response.parse() + assert_matches_type(Network, network, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.networks.with_streaming_response.get( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network = response.parse() + assert_matches_type(Network, network, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `network_id` but received ''"): + client.cloud.networks.with_raw_response.get( + network_id="", + project_id=1, + region_id=1, + ) + + +class TestAsyncNetworks: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + network = await async_client.cloud.networks.create( + project_id=1, + region_id=1, + name="my network", + ) + assert_matches_type(TaskIDList, network, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + network = await async_client.cloud.networks.create( + project_id=1, + region_id=1, + name="my network", + create_router=True, + tags={"my-tag": "my-tag-value"}, + type="vxlan", + ) + assert_matches_type(TaskIDList, network, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.with_raw_response.create( + project_id=1, + region_id=1, + name="my network", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network = await response.parse() + assert_matches_type(TaskIDList, network, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.with_streaming_response.create( + project_id=1, + region_id=1, + name="my network", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network = await response.parse() + assert_matches_type(TaskIDList, network, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + network = await async_client.cloud.networks.update( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + assert_matches_type(Network, network, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + network = await async_client.cloud.networks.update( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + name="some_name", + tags={}, + ) + assert_matches_type(Network, network, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.with_raw_response.update( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network = await response.parse() + assert_matches_type(Network, network, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.with_streaming_response.update( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network = await response.parse() + assert_matches_type(Network, network, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `network_id` but received ''"): + await async_client.cloud.networks.with_raw_response.update( + network_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + network = await async_client.cloud.networks.list( + project_id=1, + region_id=1, + ) + assert_matches_type(AsyncOffsetPage[Network], network, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + network = await async_client.cloud.networks.list( + project_id=1, + region_id=1, + limit=1000, + name="my-network", + offset=0, + order_by="created_at.desc", + tag_key=["key1", "key2"], + tag_key_value="tag_key_value", + ) + assert_matches_type(AsyncOffsetPage[Network], network, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network = await response.parse() + assert_matches_type(AsyncOffsetPage[Network], network, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network = await response.parse() + assert_matches_type(AsyncOffsetPage[Network], network, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + network = await async_client.cloud.networks.delete( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, network, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.with_raw_response.delete( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network = await response.parse() + assert_matches_type(TaskIDList, network, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.with_streaming_response.delete( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network = await response.parse() + assert_matches_type(TaskIDList, network, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `network_id` but received ''"): + await async_client.cloud.networks.with_raw_response.delete( + network_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + network = await async_client.cloud.networks.get( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + assert_matches_type(Network, network, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.networks.with_raw_response.get( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network = await response.parse() + assert_matches_type(Network, network, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.networks.with_streaming_response.get( + network_id="b39792c3-3160-4356-912e-ba396c95cdcf", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network = await response.parse() + assert_matches_type(Network, network, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `network_id` but received ''"): + await async_client.cloud.networks.with_raw_response.get( + network_id="", + project_id=1, + region_id=1, + ) diff --git a/tests/api_resources/cloud/test_placement_groups.py b/tests/api_resources/cloud/test_placement_groups.py new file mode 100644 index 00000000..84783508 --- /dev/null +++ b/tests/api_resources/cloud/test_placement_groups.py @@ -0,0 +1,356 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import TaskIDList, PlacementGroup, PlacementGroupList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPlacementGroups: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + placement_group = client.cloud.placement_groups.create( + project_id=0, + region_id=0, + name="my-server-group", + policy="anti-affinity", + ) + assert_matches_type(PlacementGroup, placement_group, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.placement_groups.with_raw_response.create( + project_id=0, + region_id=0, + name="my-server-group", + policy="anti-affinity", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + placement_group = response.parse() + assert_matches_type(PlacementGroup, placement_group, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.placement_groups.with_streaming_response.create( + project_id=0, + region_id=0, + name="my-server-group", + policy="anti-affinity", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + placement_group = response.parse() + assert_matches_type(PlacementGroup, placement_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + placement_group = client.cloud.placement_groups.list( + project_id=0, + region_id=0, + ) + assert_matches_type(PlacementGroupList, placement_group, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.placement_groups.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + placement_group = response.parse() + assert_matches_type(PlacementGroupList, placement_group, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.placement_groups.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + placement_group = response.parse() + assert_matches_type(PlacementGroupList, placement_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + placement_group = client.cloud.placement_groups.delete( + group_id="group_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, placement_group, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.placement_groups.with_raw_response.delete( + group_id="group_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + placement_group = response.parse() + assert_matches_type(TaskIDList, placement_group, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.placement_groups.with_streaming_response.delete( + group_id="group_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + placement_group = response.parse() + assert_matches_type(TaskIDList, placement_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.cloud.placement_groups.with_raw_response.delete( + group_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + placement_group = client.cloud.placement_groups.get( + group_id="group_id", + project_id=0, + region_id=0, + ) + assert_matches_type(PlacementGroup, placement_group, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.placement_groups.with_raw_response.get( + group_id="group_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + placement_group = response.parse() + assert_matches_type(PlacementGroup, placement_group, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.placement_groups.with_streaming_response.get( + group_id="group_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + placement_group = response.parse() + assert_matches_type(PlacementGroup, placement_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.cloud.placement_groups.with_raw_response.get( + group_id="", + project_id=0, + region_id=0, + ) + + +class TestAsyncPlacementGroups: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + placement_group = await async_client.cloud.placement_groups.create( + project_id=0, + region_id=0, + name="my-server-group", + policy="anti-affinity", + ) + assert_matches_type(PlacementGroup, placement_group, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.placement_groups.with_raw_response.create( + project_id=0, + region_id=0, + name="my-server-group", + policy="anti-affinity", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + placement_group = await response.parse() + assert_matches_type(PlacementGroup, placement_group, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.placement_groups.with_streaming_response.create( + project_id=0, + region_id=0, + name="my-server-group", + policy="anti-affinity", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + placement_group = await response.parse() + assert_matches_type(PlacementGroup, placement_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + placement_group = await async_client.cloud.placement_groups.list( + project_id=0, + region_id=0, + ) + assert_matches_type(PlacementGroupList, placement_group, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.placement_groups.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + placement_group = await response.parse() + assert_matches_type(PlacementGroupList, placement_group, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.placement_groups.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + placement_group = await response.parse() + assert_matches_type(PlacementGroupList, placement_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + placement_group = await async_client.cloud.placement_groups.delete( + group_id="group_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, placement_group, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.placement_groups.with_raw_response.delete( + group_id="group_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + placement_group = await response.parse() + assert_matches_type(TaskIDList, placement_group, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.placement_groups.with_streaming_response.delete( + group_id="group_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + placement_group = await response.parse() + assert_matches_type(TaskIDList, placement_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.cloud.placement_groups.with_raw_response.delete( + group_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + placement_group = await async_client.cloud.placement_groups.get( + group_id="group_id", + project_id=0, + region_id=0, + ) + assert_matches_type(PlacementGroup, placement_group, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.placement_groups.with_raw_response.get( + group_id="group_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + placement_group = await response.parse() + assert_matches_type(PlacementGroup, placement_group, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.placement_groups.with_streaming_response.get( + group_id="group_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + placement_group = await response.parse() + assert_matches_type(PlacementGroup, placement_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.cloud.placement_groups.with_raw_response.get( + group_id="", + project_id=0, + region_id=0, + ) diff --git a/tests/api_resources/cloud/test_projects.py b/tests/api_resources/cloud/test_projects.py new file mode 100644 index 00000000..3a4da5cc --- /dev/null +++ b/tests/api_resources/cloud/test_projects.py @@ -0,0 +1,381 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import Project, TaskIDList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestProjects: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + project = client.cloud.projects.create( + name="my-project", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + project = client.cloud.projects.create( + name="my-project", + description="Project description", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.projects.with_raw_response.create( + name="my-project", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.projects.with_streaming_response.create( + name="my-project", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + project = client.cloud.projects.update( + project_id=4, + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + project = client.cloud.projects.update( + project_id=4, + description="Project description", + name="my-project", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.projects.with_raw_response.update( + project_id=4, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.projects.with_streaming_response.update( + project_id=4, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + project = client.cloud.projects.list() + assert_matches_type(SyncOffsetPage[Project], project, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + project = client.cloud.projects.list( + client_id=1, + include_deleted=False, + limit=100, + name="my-project", + offset=0, + order_by="name.desc", + ) + assert_matches_type(SyncOffsetPage[Project], project, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.projects.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(SyncOffsetPage[Project], project, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.projects.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(SyncOffsetPage[Project], project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + project = client.cloud.projects.delete( + project_id=4, + ) + assert_matches_type(TaskIDList, project, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.projects.with_raw_response.delete( + project_id=4, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(TaskIDList, project, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.projects.with_streaming_response.delete( + project_id=4, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(TaskIDList, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + project = client.cloud.projects.get( + project_id=4, + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.projects.with_raw_response.get( + project_id=4, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.projects.with_streaming_response.get( + project_id=4, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncProjects: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + project = await async_client.cloud.projects.create( + name="my-project", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + project = await async_client.cloud.projects.create( + name="my-project", + description="Project description", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.projects.with_raw_response.create( + name="my-project", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.projects.with_streaming_response.create( + name="my-project", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + project = await async_client.cloud.projects.update( + project_id=4, + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + project = await async_client.cloud.projects.update( + project_id=4, + description="Project description", + name="my-project", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.projects.with_raw_response.update( + project_id=4, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.projects.with_streaming_response.update( + project_id=4, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + project = await async_client.cloud.projects.list() + assert_matches_type(AsyncOffsetPage[Project], project, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + project = await async_client.cloud.projects.list( + client_id=1, + include_deleted=False, + limit=100, + name="my-project", + offset=0, + order_by="name.desc", + ) + assert_matches_type(AsyncOffsetPage[Project], project, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.projects.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(AsyncOffsetPage[Project], project, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.projects.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(AsyncOffsetPage[Project], project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + project = await async_client.cloud.projects.delete( + project_id=4, + ) + assert_matches_type(TaskIDList, project, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.projects.with_raw_response.delete( + project_id=4, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(TaskIDList, project, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.projects.with_streaming_response.delete( + project_id=4, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(TaskIDList, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + project = await async_client.cloud.projects.get( + project_id=4, + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.projects.with_raw_response.get( + project_id=4, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.projects.with_streaming_response.get( + project_id=4, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/test_quotas.py b/tests/api_resources/cloud/test_quotas.py new file mode 100644 index 00000000..b027378e --- /dev/null +++ b/tests/api_resources/cloud/test_quotas.py @@ -0,0 +1,204 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import QuotaGetAllResponse, QuotaGetGlobalResponse, QuotaGetByRegionResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestQuotas: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_all(self, client: Gcore) -> None: + quota = client.cloud.quotas.get_all() + assert_matches_type(QuotaGetAllResponse, quota, path=["response"]) + + @parametrize + def test_raw_response_get_all(self, client: Gcore) -> None: + response = client.cloud.quotas.with_raw_response.get_all() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + quota = response.parse() + assert_matches_type(QuotaGetAllResponse, quota, path=["response"]) + + @parametrize + def test_streaming_response_get_all(self, client: Gcore) -> None: + with client.cloud.quotas.with_streaming_response.get_all() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + quota = response.parse() + assert_matches_type(QuotaGetAllResponse, quota, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_by_region(self, client: Gcore) -> None: + quota = client.cloud.quotas.get_by_region( + client_id=3, + region_id=1, + ) + assert_matches_type(QuotaGetByRegionResponse, quota, path=["response"]) + + @parametrize + def test_raw_response_get_by_region(self, client: Gcore) -> None: + response = client.cloud.quotas.with_raw_response.get_by_region( + client_id=3, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + quota = response.parse() + assert_matches_type(QuotaGetByRegionResponse, quota, path=["response"]) + + @parametrize + def test_streaming_response_get_by_region(self, client: Gcore) -> None: + with client.cloud.quotas.with_streaming_response.get_by_region( + client_id=3, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + quota = response.parse() + assert_matches_type(QuotaGetByRegionResponse, quota, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_global(self, client: Gcore) -> None: + quota = client.cloud.quotas.get_global( + 3, + ) + assert_matches_type(QuotaGetGlobalResponse, quota, path=["response"]) + + @parametrize + def test_raw_response_get_global(self, client: Gcore) -> None: + response = client.cloud.quotas.with_raw_response.get_global( + 3, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + quota = response.parse() + assert_matches_type(QuotaGetGlobalResponse, quota, path=["response"]) + + @parametrize + def test_streaming_response_get_global(self, client: Gcore) -> None: + with client.cloud.quotas.with_streaming_response.get_global( + 3, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + quota = response.parse() + assert_matches_type(QuotaGetGlobalResponse, quota, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncQuotas: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_all(self, async_client: AsyncGcore) -> None: + quota = await async_client.cloud.quotas.get_all() + assert_matches_type(QuotaGetAllResponse, quota, path=["response"]) + + @parametrize + async def test_raw_response_get_all(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.quotas.with_raw_response.get_all() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + quota = await response.parse() + assert_matches_type(QuotaGetAllResponse, quota, path=["response"]) + + @parametrize + async def test_streaming_response_get_all(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.quotas.with_streaming_response.get_all() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + quota = await response.parse() + assert_matches_type(QuotaGetAllResponse, quota, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_by_region(self, async_client: AsyncGcore) -> None: + quota = await async_client.cloud.quotas.get_by_region( + client_id=3, + region_id=1, + ) + assert_matches_type(QuotaGetByRegionResponse, quota, path=["response"]) + + @parametrize + async def test_raw_response_get_by_region(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.quotas.with_raw_response.get_by_region( + client_id=3, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + quota = await response.parse() + assert_matches_type(QuotaGetByRegionResponse, quota, path=["response"]) + + @parametrize + async def test_streaming_response_get_by_region(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.quotas.with_streaming_response.get_by_region( + client_id=3, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + quota = await response.parse() + assert_matches_type(QuotaGetByRegionResponse, quota, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_global(self, async_client: AsyncGcore) -> None: + quota = await async_client.cloud.quotas.get_global( + 3, + ) + assert_matches_type(QuotaGetGlobalResponse, quota, path=["response"]) + + @parametrize + async def test_raw_response_get_global(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.quotas.with_raw_response.get_global( + 3, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + quota = await response.parse() + assert_matches_type(QuotaGetGlobalResponse, quota, path=["response"]) + + @parametrize + async def test_streaming_response_get_global(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.quotas.with_streaming_response.get_global( + 3, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + quota = await response.parse() + assert_matches_type(QuotaGetGlobalResponse, quota, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/test_regions.py b/tests/api_resources/cloud/test_regions.py new file mode 100644 index 00000000..9f31384c --- /dev/null +++ b/tests/api_resources/cloud/test_regions.py @@ -0,0 +1,175 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import Region + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRegions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + region = client.cloud.regions.list() + assert_matches_type(SyncOffsetPage[Region], region, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + region = client.cloud.regions.list( + limit=100, + offset=0, + order_by="created_at.desc", + product="inference", + show_volume_types=False, + ) + assert_matches_type(SyncOffsetPage[Region], region, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.regions.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + region = response.parse() + assert_matches_type(SyncOffsetPage[Region], region, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.regions.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + region = response.parse() + assert_matches_type(SyncOffsetPage[Region], region, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + region = client.cloud.regions.get( + region_id=11, + ) + assert_matches_type(Region, region, path=["response"]) + + @parametrize + def test_method_get_with_all_params(self, client: Gcore) -> None: + region = client.cloud.regions.get( + region_id=11, + show_volume_types=False, + ) + assert_matches_type(Region, region, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.regions.with_raw_response.get( + region_id=11, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + region = response.parse() + assert_matches_type(Region, region, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.regions.with_streaming_response.get( + region_id=11, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + region = response.parse() + assert_matches_type(Region, region, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncRegions: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + region = await async_client.cloud.regions.list() + assert_matches_type(AsyncOffsetPage[Region], region, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + region = await async_client.cloud.regions.list( + limit=100, + offset=0, + order_by="created_at.desc", + product="inference", + show_volume_types=False, + ) + assert_matches_type(AsyncOffsetPage[Region], region, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.regions.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + region = await response.parse() + assert_matches_type(AsyncOffsetPage[Region], region, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.regions.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + region = await response.parse() + assert_matches_type(AsyncOffsetPage[Region], region, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + region = await async_client.cloud.regions.get( + region_id=11, + ) + assert_matches_type(Region, region, path=["response"]) + + @parametrize + async def test_method_get_with_all_params(self, async_client: AsyncGcore) -> None: + region = await async_client.cloud.regions.get( + region_id=11, + show_volume_types=False, + ) + assert_matches_type(Region, region, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.regions.with_raw_response.get( + region_id=11, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + region = await response.parse() + assert_matches_type(Region, region, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.regions.with_streaming_response.get( + region_id=11, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + region = await response.parse() + assert_matches_type(Region, region, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/test_registries.py b/tests/api_resources/cloud/test_registries.py new file mode 100644 index 00000000..8d2be038 --- /dev/null +++ b/tests/api_resources/cloud/test_registries.py @@ -0,0 +1,428 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import Registry, RegistryList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRegistries: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + registry = client.cloud.registries.create( + project_id=0, + region_id=0, + name="reg-home1", + ) + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + registry = client.cloud.registries.create( + project_id=0, + region_id=0, + name="reg-home1", + storage_limit=5, + ) + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.registries.with_raw_response.create( + project_id=0, + region_id=0, + name="reg-home1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry = response.parse() + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.registries.with_streaming_response.create( + project_id=0, + region_id=0, + name="reg-home1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry = response.parse() + assert_matches_type(Registry, registry, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + registry = client.cloud.registries.list( + project_id=0, + region_id=0, + ) + assert_matches_type(RegistryList, registry, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.registries.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry = response.parse() + assert_matches_type(RegistryList, registry, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.registries.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry = response.parse() + assert_matches_type(RegistryList, registry, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + registry = client.cloud.registries.delete( + registry_id=0, + project_id=0, + region_id=0, + ) + assert registry is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.registries.with_raw_response.delete( + registry_id=0, + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry = response.parse() + assert registry is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.registries.with_streaming_response.delete( + registry_id=0, + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry = response.parse() + assert registry is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + registry = client.cloud.registries.get( + registry_id=0, + project_id=0, + region_id=0, + ) + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.registries.with_raw_response.get( + registry_id=0, + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry = response.parse() + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.registries.with_streaming_response.get( + registry_id=0, + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry = response.parse() + assert_matches_type(Registry, registry, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_resize(self, client: Gcore) -> None: + registry = client.cloud.registries.resize( + registry_id=0, + project_id=0, + region_id=0, + ) + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + def test_method_resize_with_all_params(self, client: Gcore) -> None: + registry = client.cloud.registries.resize( + registry_id=0, + project_id=0, + region_id=0, + storage_limit=5, + ) + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + def test_raw_response_resize(self, client: Gcore) -> None: + response = client.cloud.registries.with_raw_response.resize( + registry_id=0, + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry = response.parse() + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + def test_streaming_response_resize(self, client: Gcore) -> None: + with client.cloud.registries.with_streaming_response.resize( + registry_id=0, + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry = response.parse() + assert_matches_type(Registry, registry, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncRegistries: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + registry = await async_client.cloud.registries.create( + project_id=0, + region_id=0, + name="reg-home1", + ) + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + registry = await async_client.cloud.registries.create( + project_id=0, + region_id=0, + name="reg-home1", + storage_limit=5, + ) + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.with_raw_response.create( + project_id=0, + region_id=0, + name="reg-home1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry = await response.parse() + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.with_streaming_response.create( + project_id=0, + region_id=0, + name="reg-home1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry = await response.parse() + assert_matches_type(Registry, registry, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + registry = await async_client.cloud.registries.list( + project_id=0, + region_id=0, + ) + assert_matches_type(RegistryList, registry, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry = await response.parse() + assert_matches_type(RegistryList, registry, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry = await response.parse() + assert_matches_type(RegistryList, registry, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + registry = await async_client.cloud.registries.delete( + registry_id=0, + project_id=0, + region_id=0, + ) + assert registry is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.with_raw_response.delete( + registry_id=0, + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry = await response.parse() + assert registry is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.with_streaming_response.delete( + registry_id=0, + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry = await response.parse() + assert registry is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + registry = await async_client.cloud.registries.get( + registry_id=0, + project_id=0, + region_id=0, + ) + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.with_raw_response.get( + registry_id=0, + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry = await response.parse() + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.with_streaming_response.get( + registry_id=0, + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry = await response.parse() + assert_matches_type(Registry, registry, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_resize(self, async_client: AsyncGcore) -> None: + registry = await async_client.cloud.registries.resize( + registry_id=0, + project_id=0, + region_id=0, + ) + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + async def test_method_resize_with_all_params(self, async_client: AsyncGcore) -> None: + registry = await async_client.cloud.registries.resize( + registry_id=0, + project_id=0, + region_id=0, + storage_limit=5, + ) + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + async def test_raw_response_resize(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.registries.with_raw_response.resize( + registry_id=0, + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + registry = await response.parse() + assert_matches_type(Registry, registry, path=["response"]) + + @parametrize + async def test_streaming_response_resize(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.registries.with_streaming_response.resize( + registry_id=0, + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + registry = await response.parse() + assert_matches_type(Registry, registry, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/test_reserved_fixed_ips.py b/tests/api_resources/cloud/test_reserved_fixed_ips.py new file mode 100644 index 00000000..21a89074 --- /dev/null +++ b/tests/api_resources/cloud/test_reserved_fixed_ips.py @@ -0,0 +1,906 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import ( + TaskIDList, + ReservedFixedIP, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestReservedFixedIPs: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create_overload_1(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + type="external", + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_1(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + type="external", + ip_family="dual", + is_vip=False, + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_raw_response_create_overload_1(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.with_raw_response.create( + project_id=0, + region_id=0, + type="external", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_1(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.with_streaming_response.create( + project_id=0, + region_id=0, + type="external", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_2(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="subnet", + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_2(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="subnet", + is_vip=False, + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_raw_response_create_overload_2(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.with_raw_response.create( + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="subnet", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_2(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.with_streaming_response.create( + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="subnet", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_3(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="any_subnet", + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_3(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="any_subnet", + ip_family="dual", + is_vip=False, + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_raw_response_create_overload_3(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.with_raw_response.create( + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="any_subnet", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_3(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.with_streaming_response.create( + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="any_subnet", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_4(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + ip_address="192.168.123.20", + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="ip_address", + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_4(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + ip_address="192.168.123.20", + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="ip_address", + is_vip=False, + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_raw_response_create_overload_4(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.with_raw_response.create( + project_id=0, + region_id=0, + ip_address="192.168.123.20", + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="ip_address", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_4(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.with_streaming_response.create( + project_id=0, + region_id=0, + ip_address="192.168.123.20", + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="ip_address", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_5(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + port_id="77f1394f-2a18-4686-a2eb-acea25146374", + type="port", + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_raw_response_create_overload_5(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.with_raw_response.create( + project_id=0, + region_id=0, + port_id="77f1394f-2a18-4686-a2eb-acea25146374", + type="port", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_5(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.with_streaming_response.create( + project_id=0, + region_id=0, + port_id="77f1394f-2a18-4686-a2eb-acea25146374", + type="port", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.update( + port_id="port_id", + project_id=0, + region_id=0, + is_vip=True, + ) + assert_matches_type(ReservedFixedIP, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.with_raw_response.update( + port_id="port_id", + project_id=0, + region_id=0, + is_vip=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = response.parse() + assert_matches_type(ReservedFixedIP, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.with_streaming_response.update( + port_id="port_id", + project_id=0, + region_id=0, + is_vip=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = response.parse() + assert_matches_type(ReservedFixedIP, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + client.cloud.reserved_fixed_ips.with_raw_response.update( + port_id="", + project_id=0, + region_id=0, + is_vip=True, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.list( + project_id=0, + region_id=0, + ) + assert_matches_type(SyncOffsetPage[ReservedFixedIP], reserved_fixed_ip, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.list( + project_id=0, + region_id=0, + available_only=True, + device_id="device_id", + external_only=True, + internal_only=True, + ip_address="ip_address", + limit=0, + offset=0, + order_by="order_by", + vip_only=True, + ) + assert_matches_type(SyncOffsetPage[ReservedFixedIP], reserved_fixed_ip, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = response.parse() + assert_matches_type(SyncOffsetPage[ReservedFixedIP], reserved_fixed_ip, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = response.parse() + assert_matches_type(SyncOffsetPage[ReservedFixedIP], reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.delete( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.with_raw_response.delete( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.with_streaming_response.delete( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + client.cloud.reserved_fixed_ips.with_raw_response.delete( + port_id="", + project_id=0, + region_id=0, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + reserved_fixed_ip = client.cloud.reserved_fixed_ips.get( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(ReservedFixedIP, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.reserved_fixed_ips.with_raw_response.get( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = response.parse() + assert_matches_type(ReservedFixedIP, reserved_fixed_ip, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.reserved_fixed_ips.with_streaming_response.get( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = response.parse() + assert_matches_type(ReservedFixedIP, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + client.cloud.reserved_fixed_ips.with_raw_response.get( + port_id="", + project_id=0, + region_id=0, + ) + + +class TestAsyncReservedFixedIPs: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create_overload_1(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + type="external", + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_1(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + type="external", + ip_family="dual", + is_vip=False, + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.with_raw_response.create( + project_id=0, + region_id=0, + type="external", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = await response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.with_streaming_response.create( + project_id=0, + region_id=0, + type="external", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = await response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_2(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="subnet", + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_2(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="subnet", + is_vip=False, + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.with_raw_response.create( + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="subnet", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = await response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.with_streaming_response.create( + project_id=0, + region_id=0, + subnet_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="subnet", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = await response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_3(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="any_subnet", + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_3(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="any_subnet", + ip_family="dual", + is_vip=False, + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_3(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.with_raw_response.create( + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="any_subnet", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = await response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_3(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.with_streaming_response.create( + project_id=0, + region_id=0, + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="any_subnet", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = await response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_4(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + ip_address="192.168.123.20", + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="ip_address", + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_4(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + ip_address="192.168.123.20", + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="ip_address", + is_vip=False, + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_4(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.with_raw_response.create( + project_id=0, + region_id=0, + ip_address="192.168.123.20", + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="ip_address", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = await response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_4(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.with_streaming_response.create( + project_id=0, + region_id=0, + ip_address="192.168.123.20", + network_id="e3c6ee77-48cb-416b-b204-11b492cc776e3", + type="ip_address", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = await response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_5(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.create( + project_id=0, + region_id=0, + port_id="77f1394f-2a18-4686-a2eb-acea25146374", + type="port", + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_5(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.with_raw_response.create( + project_id=0, + region_id=0, + port_id="77f1394f-2a18-4686-a2eb-acea25146374", + type="port", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = await response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_5(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.with_streaming_response.create( + project_id=0, + region_id=0, + port_id="77f1394f-2a18-4686-a2eb-acea25146374", + type="port", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = await response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.update( + port_id="port_id", + project_id=0, + region_id=0, + is_vip=True, + ) + assert_matches_type(ReservedFixedIP, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.with_raw_response.update( + port_id="port_id", + project_id=0, + region_id=0, + is_vip=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = await response.parse() + assert_matches_type(ReservedFixedIP, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.with_streaming_response.update( + port_id="port_id", + project_id=0, + region_id=0, + is_vip=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = await response.parse() + assert_matches_type(ReservedFixedIP, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + await async_client.cloud.reserved_fixed_ips.with_raw_response.update( + port_id="", + project_id=0, + region_id=0, + is_vip=True, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.list( + project_id=0, + region_id=0, + ) + assert_matches_type(AsyncOffsetPage[ReservedFixedIP], reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.list( + project_id=0, + region_id=0, + available_only=True, + device_id="device_id", + external_only=True, + internal_only=True, + ip_address="ip_address", + limit=0, + offset=0, + order_by="order_by", + vip_only=True, + ) + assert_matches_type(AsyncOffsetPage[ReservedFixedIP], reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.with_raw_response.list( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = await response.parse() + assert_matches_type(AsyncOffsetPage[ReservedFixedIP], reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.with_streaming_response.list( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = await response.parse() + assert_matches_type(AsyncOffsetPage[ReservedFixedIP], reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.delete( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.with_raw_response.delete( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = await response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.with_streaming_response.delete( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = await response.parse() + assert_matches_type(TaskIDList, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + await async_client.cloud.reserved_fixed_ips.with_raw_response.delete( + port_id="", + project_id=0, + region_id=0, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + reserved_fixed_ip = await async_client.cloud.reserved_fixed_ips.get( + port_id="port_id", + project_id=0, + region_id=0, + ) + assert_matches_type(ReservedFixedIP, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.reserved_fixed_ips.with_raw_response.get( + port_id="port_id", + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reserved_fixed_ip = await response.parse() + assert_matches_type(ReservedFixedIP, reserved_fixed_ip, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.reserved_fixed_ips.with_streaming_response.get( + port_id="port_id", + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reserved_fixed_ip = await response.parse() + assert_matches_type(ReservedFixedIP, reserved_fixed_ip, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `port_id` but received ''"): + await async_client.cloud.reserved_fixed_ips.with_raw_response.get( + port_id="", + project_id=0, + region_id=0, + ) diff --git a/tests/api_resources/cloud/test_secrets.py b/tests/api_resources/cloud/test_secrets.py new file mode 100644 index 00000000..2563b0f7 --- /dev/null +++ b/tests/api_resources/cloud/test_secrets.py @@ -0,0 +1,432 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import Secret, TaskIDList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSecrets: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + secret = client.cloud.secrets.list( + project_id=1, + region_id=1, + ) + assert_matches_type(SyncOffsetPage[Secret], secret, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + secret = client.cloud.secrets.list( + project_id=1, + region_id=1, + limit=1000, + offset=0, + ) + assert_matches_type(SyncOffsetPage[Secret], secret, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.secrets.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(SyncOffsetPage[Secret], secret, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.secrets.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(SyncOffsetPage[Secret], secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + secret = client.cloud.secrets.delete( + secret_id="bfc7824b-31b6-4a28-a0c4-7df137139215", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, secret, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.secrets.with_raw_response.delete( + secret_id="bfc7824b-31b6-4a28-a0c4-7df137139215", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(TaskIDList, secret, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.secrets.with_streaming_response.delete( + secret_id="bfc7824b-31b6-4a28-a0c4-7df137139215", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(TaskIDList, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `secret_id` but received ''"): + client.cloud.secrets.with_raw_response.delete( + secret_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + secret = client.cloud.secrets.get( + secret_id="bfc7824b-31b6-4a28-a0c4-7df137139215", + project_id=1, + region_id=1, + ) + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.secrets.with_raw_response.get( + secret_id="bfc7824b-31b6-4a28-a0c4-7df137139215", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.secrets.with_streaming_response.get( + secret_id="bfc7824b-31b6-4a28-a0c4-7df137139215", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `secret_id` but received ''"): + client.cloud.secrets.with_raw_response.get( + secret_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_upload_tls_certificate(self, client: Gcore) -> None: + secret = client.cloud.secrets.upload_tls_certificate( + project_id=1, + region_id=1, + name="Load balancer certificate #1", + payload={ + "certificate": "", + "certificate_chain": "", + "private_key": "", + }, + ) + assert_matches_type(TaskIDList, secret, path=["response"]) + + @parametrize + def test_method_upload_tls_certificate_with_all_params(self, client: Gcore) -> None: + secret = client.cloud.secrets.upload_tls_certificate( + project_id=1, + region_id=1, + name="Load balancer certificate #1", + payload={ + "certificate": "", + "certificate_chain": "", + "private_key": "", + }, + expiration=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(TaskIDList, secret, path=["response"]) + + @parametrize + def test_raw_response_upload_tls_certificate(self, client: Gcore) -> None: + response = client.cloud.secrets.with_raw_response.upload_tls_certificate( + project_id=1, + region_id=1, + name="Load balancer certificate #1", + payload={ + "certificate": "", + "certificate_chain": "", + "private_key": "", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(TaskIDList, secret, path=["response"]) + + @parametrize + def test_streaming_response_upload_tls_certificate(self, client: Gcore) -> None: + with client.cloud.secrets.with_streaming_response.upload_tls_certificate( + project_id=1, + region_id=1, + name="Load balancer certificate #1", + payload={ + "certificate": "", + "certificate_chain": "", + "private_key": "", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(TaskIDList, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncSecrets: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + secret = await async_client.cloud.secrets.list( + project_id=1, + region_id=1, + ) + assert_matches_type(AsyncOffsetPage[Secret], secret, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + secret = await async_client.cloud.secrets.list( + project_id=1, + region_id=1, + limit=1000, + offset=0, + ) + assert_matches_type(AsyncOffsetPage[Secret], secret, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.secrets.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(AsyncOffsetPage[Secret], secret, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.secrets.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(AsyncOffsetPage[Secret], secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + secret = await async_client.cloud.secrets.delete( + secret_id="bfc7824b-31b6-4a28-a0c4-7df137139215", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, secret, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.secrets.with_raw_response.delete( + secret_id="bfc7824b-31b6-4a28-a0c4-7df137139215", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(TaskIDList, secret, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.secrets.with_streaming_response.delete( + secret_id="bfc7824b-31b6-4a28-a0c4-7df137139215", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(TaskIDList, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `secret_id` but received ''"): + await async_client.cloud.secrets.with_raw_response.delete( + secret_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + secret = await async_client.cloud.secrets.get( + secret_id="bfc7824b-31b6-4a28-a0c4-7df137139215", + project_id=1, + region_id=1, + ) + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.secrets.with_raw_response.get( + secret_id="bfc7824b-31b6-4a28-a0c4-7df137139215", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.secrets.with_streaming_response.get( + secret_id="bfc7824b-31b6-4a28-a0c4-7df137139215", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `secret_id` but received ''"): + await async_client.cloud.secrets.with_raw_response.get( + secret_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_upload_tls_certificate(self, async_client: AsyncGcore) -> None: + secret = await async_client.cloud.secrets.upload_tls_certificate( + project_id=1, + region_id=1, + name="Load balancer certificate #1", + payload={ + "certificate": "", + "certificate_chain": "", + "private_key": "", + }, + ) + assert_matches_type(TaskIDList, secret, path=["response"]) + + @parametrize + async def test_method_upload_tls_certificate_with_all_params(self, async_client: AsyncGcore) -> None: + secret = await async_client.cloud.secrets.upload_tls_certificate( + project_id=1, + region_id=1, + name="Load balancer certificate #1", + payload={ + "certificate": "", + "certificate_chain": "", + "private_key": "", + }, + expiration=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(TaskIDList, secret, path=["response"]) + + @parametrize + async def test_raw_response_upload_tls_certificate(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.secrets.with_raw_response.upload_tls_certificate( + project_id=1, + region_id=1, + name="Load balancer certificate #1", + payload={ + "certificate": "", + "certificate_chain": "", + "private_key": "", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(TaskIDList, secret, path=["response"]) + + @parametrize + async def test_streaming_response_upload_tls_certificate(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.secrets.with_streaming_response.upload_tls_certificate( + project_id=1, + region_id=1, + name="Load balancer certificate #1", + payload={ + "certificate": "", + "certificate_chain": "", + "private_key": "", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(TaskIDList, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/test_security_groups.py b/tests/api_resources/cloud/test_security_groups.py new file mode 100644 index 00000000..6050ff4c --- /dev/null +++ b/tests/api_resources/cloud/test_security_groups.py @@ -0,0 +1,758 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import ( + TaskIDList, + SecurityGroup, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSecurityGroups: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + security_group = client.cloud.security_groups.create( + project_id=1, + region_id=1, + name="my_security_group", + ) + assert_matches_type(TaskIDList, security_group, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + security_group = client.cloud.security_groups.create( + project_id=1, + region_id=1, + name="my_security_group", + description="My security group description", + rules=[ + { + "direction": "ingress", + "description": "Some description", + "ethertype": "IPv4", + "port_range_max": 80, + "port_range_min": 80, + "protocol": "tcp", + "remote_group_id": "00000000-0000-4000-8000-000000000000", + "remote_ip_prefix": "10.0.0.0/8", + } + ], + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, security_group, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.security_groups.with_raw_response.create( + project_id=1, + region_id=1, + name="my_security_group", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = response.parse() + assert_matches_type(TaskIDList, security_group, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.security_groups.with_streaming_response.create( + project_id=1, + region_id=1, + name="my_security_group", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = response.parse() + assert_matches_type(TaskIDList, security_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + security_group = client.cloud.security_groups.update( + group_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, security_group, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + security_group = client.cloud.security_groups.update( + group_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + description="Some description", + name="some_name", + rules=[ + { + "description": "Some description", + "direction": "egress", + "ethertype": "IPv4", + "port_range_max": 80, + "port_range_min": 80, + "protocol": "tcp", + "remote_group_id": "00000000-0000-4000-8000-000000000000", + "remote_ip_prefix": "10.0.0.0/8", + } + ], + tags={}, + ) + assert_matches_type(TaskIDList, security_group, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.security_groups.with_raw_response.update( + group_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = response.parse() + assert_matches_type(TaskIDList, security_group, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.security_groups.with_streaming_response.update( + group_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = response.parse() + assert_matches_type(TaskIDList, security_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.cloud.security_groups.with_raw_response.update( + group_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + security_group = client.cloud.security_groups.list( + project_id=1, + region_id=1, + ) + assert_matches_type(SyncOffsetPage[SecurityGroup], security_group, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + security_group = client.cloud.security_groups.list( + project_id=1, + region_id=1, + limit=10, + name="my_security_group", + offset=0, + tag_key=["key1", "key2"], + tag_key_value="tag_key_value", + ) + assert_matches_type(SyncOffsetPage[SecurityGroup], security_group, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.security_groups.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = response.parse() + assert_matches_type(SyncOffsetPage[SecurityGroup], security_group, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.security_groups.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = response.parse() + assert_matches_type(SyncOffsetPage[SecurityGroup], security_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + security_group = client.cloud.security_groups.delete( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + assert security_group is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.security_groups.with_raw_response.delete( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = response.parse() + assert security_group is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.security_groups.with_streaming_response.delete( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = response.parse() + assert security_group is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.cloud.security_groups.with_raw_response.delete( + group_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_copy(self, client: Gcore) -> None: + security_group = client.cloud.security_groups.copy( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + name="some_name", + ) + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + @parametrize + def test_raw_response_copy(self, client: Gcore) -> None: + response = client.cloud.security_groups.with_raw_response.copy( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + name="some_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = response.parse() + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + @parametrize + def test_streaming_response_copy(self, client: Gcore) -> None: + with client.cloud.security_groups.with_streaming_response.copy( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + name="some_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = response.parse() + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_copy(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.cloud.security_groups.with_raw_response.copy( + group_id="", + project_id=1, + region_id=1, + name="some_name", + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + security_group = client.cloud.security_groups.get( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.security_groups.with_raw_response.get( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = response.parse() + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.security_groups.with_streaming_response.get( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = response.parse() + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.cloud.security_groups.with_raw_response.get( + group_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_revert_to_default(self, client: Gcore) -> None: + security_group = client.cloud.security_groups.revert_to_default( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + @parametrize + def test_raw_response_revert_to_default(self, client: Gcore) -> None: + response = client.cloud.security_groups.with_raw_response.revert_to_default( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = response.parse() + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + @parametrize + def test_streaming_response_revert_to_default(self, client: Gcore) -> None: + with client.cloud.security_groups.with_streaming_response.revert_to_default( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = response.parse() + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_revert_to_default(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.cloud.security_groups.with_raw_response.revert_to_default( + group_id="", + project_id=1, + region_id=1, + ) + + +class TestAsyncSecurityGroups: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + security_group = await async_client.cloud.security_groups.create( + project_id=1, + region_id=1, + name="my_security_group", + ) + assert_matches_type(TaskIDList, security_group, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + security_group = await async_client.cloud.security_groups.create( + project_id=1, + region_id=1, + name="my_security_group", + description="My security group description", + rules=[ + { + "direction": "ingress", + "description": "Some description", + "ethertype": "IPv4", + "port_range_max": 80, + "port_range_min": 80, + "protocol": "tcp", + "remote_group_id": "00000000-0000-4000-8000-000000000000", + "remote_ip_prefix": "10.0.0.0/8", + } + ], + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, security_group, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.security_groups.with_raw_response.create( + project_id=1, + region_id=1, + name="my_security_group", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = await response.parse() + assert_matches_type(TaskIDList, security_group, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.security_groups.with_streaming_response.create( + project_id=1, + region_id=1, + name="my_security_group", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = await response.parse() + assert_matches_type(TaskIDList, security_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + security_group = await async_client.cloud.security_groups.update( + group_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, security_group, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + security_group = await async_client.cloud.security_groups.update( + group_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + description="Some description", + name="some_name", + rules=[ + { + "description": "Some description", + "direction": "egress", + "ethertype": "IPv4", + "port_range_max": 80, + "port_range_min": 80, + "protocol": "tcp", + "remote_group_id": "00000000-0000-4000-8000-000000000000", + "remote_ip_prefix": "10.0.0.0/8", + } + ], + tags={}, + ) + assert_matches_type(TaskIDList, security_group, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.security_groups.with_raw_response.update( + group_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = await response.parse() + assert_matches_type(TaskIDList, security_group, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.security_groups.with_streaming_response.update( + group_id="00000000-0000-4000-8000-000000000000", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = await response.parse() + assert_matches_type(TaskIDList, security_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.cloud.security_groups.with_raw_response.update( + group_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + security_group = await async_client.cloud.security_groups.list( + project_id=1, + region_id=1, + ) + assert_matches_type(AsyncOffsetPage[SecurityGroup], security_group, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + security_group = await async_client.cloud.security_groups.list( + project_id=1, + region_id=1, + limit=10, + name="my_security_group", + offset=0, + tag_key=["key1", "key2"], + tag_key_value="tag_key_value", + ) + assert_matches_type(AsyncOffsetPage[SecurityGroup], security_group, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.security_groups.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = await response.parse() + assert_matches_type(AsyncOffsetPage[SecurityGroup], security_group, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.security_groups.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = await response.parse() + assert_matches_type(AsyncOffsetPage[SecurityGroup], security_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + security_group = await async_client.cloud.security_groups.delete( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + assert security_group is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.security_groups.with_raw_response.delete( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = await response.parse() + assert security_group is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.security_groups.with_streaming_response.delete( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = await response.parse() + assert security_group is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.cloud.security_groups.with_raw_response.delete( + group_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_copy(self, async_client: AsyncGcore) -> None: + security_group = await async_client.cloud.security_groups.copy( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + name="some_name", + ) + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + @parametrize + async def test_raw_response_copy(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.security_groups.with_raw_response.copy( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + name="some_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = await response.parse() + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + @parametrize + async def test_streaming_response_copy(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.security_groups.with_streaming_response.copy( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + name="some_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = await response.parse() + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_copy(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.cloud.security_groups.with_raw_response.copy( + group_id="", + project_id=1, + region_id=1, + name="some_name", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + security_group = await async_client.cloud.security_groups.get( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.security_groups.with_raw_response.get( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = await response.parse() + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.security_groups.with_streaming_response.get( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = await response.parse() + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.cloud.security_groups.with_raw_response.get( + group_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_revert_to_default(self, async_client: AsyncGcore) -> None: + security_group = await async_client.cloud.security_groups.revert_to_default( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + @parametrize + async def test_raw_response_revert_to_default(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.security_groups.with_raw_response.revert_to_default( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + security_group = await response.parse() + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + @parametrize + async def test_streaming_response_revert_to_default(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.security_groups.with_streaming_response.revert_to_default( + group_id="024a29e9-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + security_group = await response.parse() + assert_matches_type(SecurityGroup, security_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_revert_to_default(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.cloud.security_groups.with_raw_response.revert_to_default( + group_id="", + project_id=1, + region_id=1, + ) diff --git a/tests/api_resources/cloud/test_ssh_keys.py b/tests/api_resources/cloud/test_ssh_keys.py new file mode 100644 index 00000000..14428dbf --- /dev/null +++ b/tests/api_resources/cloud/test_ssh_keys.py @@ -0,0 +1,457 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import SSHKey, SSHKeyCreated + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSSHKeys: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + ssh_key = client.cloud.ssh_keys.create( + project_id=1, + name="my-ssh-key", + ) + assert_matches_type(SSHKeyCreated, ssh_key, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + ssh_key = client.cloud.ssh_keys.create( + project_id=1, + name="my-ssh-key", + public_key="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIjxL6g1II8NsO8odvBwGKvq2Dx/h/xrvsV9b9LVIYKm my-username@my-hostname", + shared_in_project=True, + ) + assert_matches_type(SSHKeyCreated, ssh_key, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.ssh_keys.with_raw_response.create( + project_id=1, + name="my-ssh-key", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ssh_key = response.parse() + assert_matches_type(SSHKeyCreated, ssh_key, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.ssh_keys.with_streaming_response.create( + project_id=1, + name="my-ssh-key", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ssh_key = response.parse() + assert_matches_type(SSHKeyCreated, ssh_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + ssh_key = client.cloud.ssh_keys.update( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + shared_in_project=True, + ) + assert_matches_type(SSHKey, ssh_key, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.ssh_keys.with_raw_response.update( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + shared_in_project=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ssh_key = response.parse() + assert_matches_type(SSHKey, ssh_key, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.ssh_keys.with_streaming_response.update( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + shared_in_project=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ssh_key = response.parse() + assert_matches_type(SSHKey, ssh_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `ssh_key_id` but received ''"): + client.cloud.ssh_keys.with_raw_response.update( + ssh_key_id="", + project_id=1, + shared_in_project=True, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + ssh_key = client.cloud.ssh_keys.list( + project_id=1, + ) + assert_matches_type(SyncOffsetPage[SSHKey], ssh_key, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + ssh_key = client.cloud.ssh_keys.list( + project_id=1, + limit=100, + name="my-ssh-key", + offset=0, + order_by="created_at.desc", + ) + assert_matches_type(SyncOffsetPage[SSHKey], ssh_key, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.ssh_keys.with_raw_response.list( + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ssh_key = response.parse() + assert_matches_type(SyncOffsetPage[SSHKey], ssh_key, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.ssh_keys.with_streaming_response.list( + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ssh_key = response.parse() + assert_matches_type(SyncOffsetPage[SSHKey], ssh_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + ssh_key = client.cloud.ssh_keys.delete( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + ) + assert ssh_key is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.ssh_keys.with_raw_response.delete( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ssh_key = response.parse() + assert ssh_key is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.ssh_keys.with_streaming_response.delete( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ssh_key = response.parse() + assert ssh_key is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `ssh_key_id` but received ''"): + client.cloud.ssh_keys.with_raw_response.delete( + ssh_key_id="", + project_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + ssh_key = client.cloud.ssh_keys.get( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + ) + assert_matches_type(SSHKey, ssh_key, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.ssh_keys.with_raw_response.get( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ssh_key = response.parse() + assert_matches_type(SSHKey, ssh_key, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.ssh_keys.with_streaming_response.get( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ssh_key = response.parse() + assert_matches_type(SSHKey, ssh_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `ssh_key_id` but received ''"): + client.cloud.ssh_keys.with_raw_response.get( + ssh_key_id="", + project_id=1, + ) + + +class TestAsyncSSHKeys: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + ssh_key = await async_client.cloud.ssh_keys.create( + project_id=1, + name="my-ssh-key", + ) + assert_matches_type(SSHKeyCreated, ssh_key, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + ssh_key = await async_client.cloud.ssh_keys.create( + project_id=1, + name="my-ssh-key", + public_key="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIjxL6g1II8NsO8odvBwGKvq2Dx/h/xrvsV9b9LVIYKm my-username@my-hostname", + shared_in_project=True, + ) + assert_matches_type(SSHKeyCreated, ssh_key, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.ssh_keys.with_raw_response.create( + project_id=1, + name="my-ssh-key", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ssh_key = await response.parse() + assert_matches_type(SSHKeyCreated, ssh_key, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.ssh_keys.with_streaming_response.create( + project_id=1, + name="my-ssh-key", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ssh_key = await response.parse() + assert_matches_type(SSHKeyCreated, ssh_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + ssh_key = await async_client.cloud.ssh_keys.update( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + shared_in_project=True, + ) + assert_matches_type(SSHKey, ssh_key, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.ssh_keys.with_raw_response.update( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + shared_in_project=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ssh_key = await response.parse() + assert_matches_type(SSHKey, ssh_key, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.ssh_keys.with_streaming_response.update( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + shared_in_project=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ssh_key = await response.parse() + assert_matches_type(SSHKey, ssh_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `ssh_key_id` but received ''"): + await async_client.cloud.ssh_keys.with_raw_response.update( + ssh_key_id="", + project_id=1, + shared_in_project=True, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + ssh_key = await async_client.cloud.ssh_keys.list( + project_id=1, + ) + assert_matches_type(AsyncOffsetPage[SSHKey], ssh_key, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + ssh_key = await async_client.cloud.ssh_keys.list( + project_id=1, + limit=100, + name="my-ssh-key", + offset=0, + order_by="created_at.desc", + ) + assert_matches_type(AsyncOffsetPage[SSHKey], ssh_key, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.ssh_keys.with_raw_response.list( + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ssh_key = await response.parse() + assert_matches_type(AsyncOffsetPage[SSHKey], ssh_key, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.ssh_keys.with_streaming_response.list( + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ssh_key = await response.parse() + assert_matches_type(AsyncOffsetPage[SSHKey], ssh_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + ssh_key = await async_client.cloud.ssh_keys.delete( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + ) + assert ssh_key is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.ssh_keys.with_raw_response.delete( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ssh_key = await response.parse() + assert ssh_key is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.ssh_keys.with_streaming_response.delete( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ssh_key = await response.parse() + assert ssh_key is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `ssh_key_id` but received ''"): + await async_client.cloud.ssh_keys.with_raw_response.delete( + ssh_key_id="", + project_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + ssh_key = await async_client.cloud.ssh_keys.get( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + ) + assert_matches_type(SSHKey, ssh_key, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.ssh_keys.with_raw_response.get( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ssh_key = await response.parse() + assert_matches_type(SSHKey, ssh_key, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.ssh_keys.with_streaming_response.get( + ssh_key_id="36a7a97a-0672-4911-8f2b-92cd4e5b0d91", + project_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ssh_key = await response.parse() + assert_matches_type(SSHKey, ssh_key, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `ssh_key_id` but received ''"): + await async_client.cloud.ssh_keys.with_raw_response.get( + ssh_key_id="", + project_id=1, + ) diff --git a/tests/api_resources/cloud/test_tasks.py b/tests/api_resources/cloud/test_tasks.py new file mode 100644 index 00000000..abe25c27 --- /dev/null +++ b/tests/api_resources/cloud/test_tasks.py @@ -0,0 +1,328 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import Task + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTasks: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + task = client.cloud.tasks.list() + assert_matches_type(SyncOffsetPage[Task], task, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + task = client.cloud.tasks.list( + from_timestamp=parse_datetime("2019-12-27T18:11:19.117Z"), + is_acknowledged=True, + limit=100, + offset=0, + order_by="asc", + project_id=[0], + region_id=[0], + sorting="asc", + state=["ERROR"], + task_type="task_type", + to_timestamp=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(SyncOffsetPage[Task], task, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.tasks.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = response.parse() + assert_matches_type(SyncOffsetPage[Task], task, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.tasks.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = response.parse() + assert_matches_type(SyncOffsetPage[Task], task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_acknowledge_all(self, client: Gcore) -> None: + task = client.cloud.tasks.acknowledge_all() + assert task is None + + @parametrize + def test_method_acknowledge_all_with_all_params(self, client: Gcore) -> None: + task = client.cloud.tasks.acknowledge_all( + project_id=0, + region_id=0, + ) + assert task is None + + @parametrize + def test_raw_response_acknowledge_all(self, client: Gcore) -> None: + response = client.cloud.tasks.with_raw_response.acknowledge_all() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = response.parse() + assert task is None + + @parametrize + def test_streaming_response_acknowledge_all(self, client: Gcore) -> None: + with client.cloud.tasks.with_streaming_response.acknowledge_all() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = response.parse() + assert task is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_acknowledge_one(self, client: Gcore) -> None: + task = client.cloud.tasks.acknowledge_one( + "task_id", + ) + assert_matches_type(Task, task, path=["response"]) + + @parametrize + def test_raw_response_acknowledge_one(self, client: Gcore) -> None: + response = client.cloud.tasks.with_raw_response.acknowledge_one( + "task_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = response.parse() + assert_matches_type(Task, task, path=["response"]) + + @parametrize + def test_streaming_response_acknowledge_one(self, client: Gcore) -> None: + with client.cloud.tasks.with_streaming_response.acknowledge_one( + "task_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = response.parse() + assert_matches_type(Task, task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_acknowledge_one(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `task_id` but received ''"): + client.cloud.tasks.with_raw_response.acknowledge_one( + "", + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + task = client.cloud.tasks.get( + "task_id", + ) + assert_matches_type(Task, task, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.tasks.with_raw_response.get( + "task_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = response.parse() + assert_matches_type(Task, task, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.tasks.with_streaming_response.get( + "task_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = response.parse() + assert_matches_type(Task, task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `task_id` but received ''"): + client.cloud.tasks.with_raw_response.get( + "", + ) + + +class TestAsyncTasks: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + task = await async_client.cloud.tasks.list() + assert_matches_type(AsyncOffsetPage[Task], task, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + task = await async_client.cloud.tasks.list( + from_timestamp=parse_datetime("2019-12-27T18:11:19.117Z"), + is_acknowledged=True, + limit=100, + offset=0, + order_by="asc", + project_id=[0], + region_id=[0], + sorting="asc", + state=["ERROR"], + task_type="task_type", + to_timestamp=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(AsyncOffsetPage[Task], task, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.tasks.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = await response.parse() + assert_matches_type(AsyncOffsetPage[Task], task, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.tasks.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = await response.parse() + assert_matches_type(AsyncOffsetPage[Task], task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_acknowledge_all(self, async_client: AsyncGcore) -> None: + task = await async_client.cloud.tasks.acknowledge_all() + assert task is None + + @parametrize + async def test_method_acknowledge_all_with_all_params(self, async_client: AsyncGcore) -> None: + task = await async_client.cloud.tasks.acknowledge_all( + project_id=0, + region_id=0, + ) + assert task is None + + @parametrize + async def test_raw_response_acknowledge_all(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.tasks.with_raw_response.acknowledge_all() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = await response.parse() + assert task is None + + @parametrize + async def test_streaming_response_acknowledge_all(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.tasks.with_streaming_response.acknowledge_all() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = await response.parse() + assert task is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_acknowledge_one(self, async_client: AsyncGcore) -> None: + task = await async_client.cloud.tasks.acknowledge_one( + "task_id", + ) + assert_matches_type(Task, task, path=["response"]) + + @parametrize + async def test_raw_response_acknowledge_one(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.tasks.with_raw_response.acknowledge_one( + "task_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = await response.parse() + assert_matches_type(Task, task, path=["response"]) + + @parametrize + async def test_streaming_response_acknowledge_one(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.tasks.with_streaming_response.acknowledge_one( + "task_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = await response.parse() + assert_matches_type(Task, task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_acknowledge_one(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `task_id` but received ''"): + await async_client.cloud.tasks.with_raw_response.acknowledge_one( + "", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + task = await async_client.cloud.tasks.get( + "task_id", + ) + assert_matches_type(Task, task, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.tasks.with_raw_response.get( + "task_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + task = await response.parse() + assert_matches_type(Task, task, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.tasks.with_streaming_response.get( + "task_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + task = await response.parse() + assert_matches_type(Task, task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `task_id` but received ''"): + await async_client.cloud.tasks.with_raw_response.get( + "", + ) diff --git a/tests/api_resources/cloud/test_usage_reports.py b/tests/api_resources/cloud/test_usage_reports.py new file mode 100644 index 00000000..76b1417d --- /dev/null +++ b/tests/api_resources/cloud/test_usage_reports.py @@ -0,0 +1,183 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.types.cloud import UsageReport + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestUsageReports: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + usage_report = client.cloud.usage_reports.get( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) + assert_matches_type(UsageReport, usage_report, path=["response"]) + + @parametrize + def test_method_get_with_all_params(self, client: Gcore) -> None: + usage_report = client.cloud.usage_reports.get( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + enable_last_day=False, + limit=10, + offset=0, + projects=[16, 17, 18, 19, 20], + regions=[1, 2, 3], + schema_filter={ + "field": "flavor", + "type": "instance", + "values": ["g1-standard-1-2"], + }, + sorting=[ + { + "billing_value": "asc", + "first_seen": "asc", + "last_name": "asc", + "last_seen": "asc", + "project": "asc", + "region": "asc", + "type": "asc", + } + ], + tags={ + "conditions": [ + { + "key": "os_version", + "strict": True, + "value": "22.04", + }, + { + "key": "os_version", + "strict": True, + "value": "23.04", + }, + ], + "condition_type": "OR", + }, + types=["egress_traffic", "instance"], + ) + assert_matches_type(UsageReport, usage_report, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.usage_reports.with_raw_response.get( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage_report = response.parse() + assert_matches_type(UsageReport, usage_report, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.usage_reports.with_streaming_response.get( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage_report = response.parse() + assert_matches_type(UsageReport, usage_report, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncUsageReports: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + usage_report = await async_client.cloud.usage_reports.get( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) + assert_matches_type(UsageReport, usage_report, path=["response"]) + + @parametrize + async def test_method_get_with_all_params(self, async_client: AsyncGcore) -> None: + usage_report = await async_client.cloud.usage_reports.get( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + enable_last_day=False, + limit=10, + offset=0, + projects=[16, 17, 18, 19, 20], + regions=[1, 2, 3], + schema_filter={ + "field": "flavor", + "type": "instance", + "values": ["g1-standard-1-2"], + }, + sorting=[ + { + "billing_value": "asc", + "first_seen": "asc", + "last_name": "asc", + "last_seen": "asc", + "project": "asc", + "region": "asc", + "type": "asc", + } + ], + tags={ + "conditions": [ + { + "key": "os_version", + "strict": True, + "value": "22.04", + }, + { + "key": "os_version", + "strict": True, + "value": "23.04", + }, + ], + "condition_type": "OR", + }, + types=["egress_traffic", "instance"], + ) + assert_matches_type(UsageReport, usage_report, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.usage_reports.with_raw_response.get( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + usage_report = await response.parse() + assert_matches_type(UsageReport, usage_report, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.usage_reports.with_streaming_response.get( + time_from=parse_datetime("2023-01-01T00:00:00Z"), + time_to=parse_datetime("2023-02-01T00:00:00Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + usage_report = await response.parse() + assert_matches_type(UsageReport, usage_report, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/cloud/test_volume_snapshots.py b/tests/api_resources/cloud/test_volume_snapshots.py new file mode 100644 index 00000000..f4da5ed7 --- /dev/null +++ b/tests/api_resources/cloud/test_volume_snapshots.py @@ -0,0 +1,429 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cloud import ( + Snapshot, + TaskIDList, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestVolumeSnapshots: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + volume_snapshot = client.cloud.volume_snapshots.create( + project_id=0, + region_id=0, + name="my-snapshot", + volume_id="67baa7d1-08ea-4fc5-bef2-6b2465b7d227", + ) + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + volume_snapshot = client.cloud.volume_snapshots.create( + project_id=0, + region_id=0, + name="my-snapshot", + volume_id="67baa7d1-08ea-4fc5-bef2-6b2465b7d227", + description="Snapshot description", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.volume_snapshots.with_raw_response.create( + project_id=0, + region_id=0, + name="my-snapshot", + volume_id="67baa7d1-08ea-4fc5-bef2-6b2465b7d227", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume_snapshot = response.parse() + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.volume_snapshots.with_streaming_response.create( + project_id=0, + region_id=0, + name="my-snapshot", + volume_id="67baa7d1-08ea-4fc5-bef2-6b2465b7d227", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume_snapshot = response.parse() + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + volume_snapshot = client.cloud.volume_snapshots.update( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + volume_snapshot = client.cloud.volume_snapshots.update( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + name="my-backup-snapshot", + tags={}, + ) + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.volume_snapshots.with_raw_response.update( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume_snapshot = response.parse() + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.volume_snapshots.with_streaming_response.update( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume_snapshot = response.parse() + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `snapshot_id` but received ''"): + client.cloud.volume_snapshots.with_raw_response.update( + snapshot_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + volume_snapshot = client.cloud.volume_snapshots.delete( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.volume_snapshots.with_raw_response.delete( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume_snapshot = response.parse() + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.volume_snapshots.with_streaming_response.delete( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume_snapshot = response.parse() + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `snapshot_id` but received ''"): + client.cloud.volume_snapshots.with_raw_response.delete( + snapshot_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + volume_snapshot = client.cloud.volume_snapshots.get( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.volume_snapshots.with_raw_response.get( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume_snapshot = response.parse() + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.volume_snapshots.with_streaming_response.get( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume_snapshot = response.parse() + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `snapshot_id` but received ''"): + client.cloud.volume_snapshots.with_raw_response.get( + snapshot_id="", + project_id=1, + region_id=1, + ) + + +class TestAsyncVolumeSnapshots: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + volume_snapshot = await async_client.cloud.volume_snapshots.create( + project_id=0, + region_id=0, + name="my-snapshot", + volume_id="67baa7d1-08ea-4fc5-bef2-6b2465b7d227", + ) + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + volume_snapshot = await async_client.cloud.volume_snapshots.create( + project_id=0, + region_id=0, + name="my-snapshot", + volume_id="67baa7d1-08ea-4fc5-bef2-6b2465b7d227", + description="Snapshot description", + tags={"my-tag": "my-tag-value"}, + ) + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volume_snapshots.with_raw_response.create( + project_id=0, + region_id=0, + name="my-snapshot", + volume_id="67baa7d1-08ea-4fc5-bef2-6b2465b7d227", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume_snapshot = await response.parse() + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volume_snapshots.with_streaming_response.create( + project_id=0, + region_id=0, + name="my-snapshot", + volume_id="67baa7d1-08ea-4fc5-bef2-6b2465b7d227", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume_snapshot = await response.parse() + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + volume_snapshot = await async_client.cloud.volume_snapshots.update( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + volume_snapshot = await async_client.cloud.volume_snapshots.update( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + name="my-backup-snapshot", + tags={}, + ) + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volume_snapshots.with_raw_response.update( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume_snapshot = await response.parse() + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volume_snapshots.with_streaming_response.update( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume_snapshot = await response.parse() + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `snapshot_id` but received ''"): + await async_client.cloud.volume_snapshots.with_raw_response.update( + snapshot_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + volume_snapshot = await async_client.cloud.volume_snapshots.delete( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volume_snapshots.with_raw_response.delete( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume_snapshot = await response.parse() + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volume_snapshots.with_streaming_response.delete( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume_snapshot = await response.parse() + assert_matches_type(TaskIDList, volume_snapshot, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `snapshot_id` but received ''"): + await async_client.cloud.volume_snapshots.with_raw_response.delete( + snapshot_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + volume_snapshot = await async_client.cloud.volume_snapshots.get( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volume_snapshots.with_raw_response.get( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume_snapshot = await response.parse() + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volume_snapshots.with_streaming_response.get( + snapshot_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume_snapshot = await response.parse() + assert_matches_type(Snapshot, volume_snapshot, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `snapshot_id` but received ''"): + await async_client.cloud.volume_snapshots.with_raw_response.get( + snapshot_id="", + project_id=1, + region_id=1, + ) diff --git a/tests/api_resources/cloud/test_volumes.py b/tests/api_resources/cloud/test_volumes.py new file mode 100644 index 00000000..67bd0e60 --- /dev/null +++ b/tests/api_resources/cloud/test_volumes.py @@ -0,0 +1,1328 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud import ( + Volume, + TaskIDList, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestVolumes: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create_overload_1(self, client: Gcore) -> None: + volume = client.cloud.volumes.create( + project_id=1, + region_id=1, + image_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + name="volume-1", + size=10, + source="image", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_1(self, client: Gcore) -> None: + volume = client.cloud.volumes.create( + project_id=1, + region_id=1, + image_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + name="volume-1", + size=10, + source="image", + attachment_tag="device-tag", + instance_id_to_attach_to="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + lifecycle_policy_ids=[1, 2], + tags={}, + type_name="standard", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_raw_response_create_overload_1(self, client: Gcore) -> None: + response = client.cloud.volumes.with_raw_response.create( + project_id=1, + region_id=1, + image_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + name="volume-1", + size=10, + source="image", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_1(self, client: Gcore) -> None: + with client.cloud.volumes.with_streaming_response.create( + project_id=1, + region_id=1, + image_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + name="volume-1", + size=10, + source="image", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_2(self, client: Gcore) -> None: + volume = client.cloud.volumes.create( + project_id=1, + region_id=1, + name="volume-1", + snapshot_id="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + source="snapshot", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_2(self, client: Gcore) -> None: + volume = client.cloud.volumes.create( + project_id=1, + region_id=1, + name="volume-1", + snapshot_id="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + source="snapshot", + attachment_tag="device-tag", + instance_id_to_attach_to="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + lifecycle_policy_ids=[1, 2], + size=10, + tags={}, + type_name="standard", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_raw_response_create_overload_2(self, client: Gcore) -> None: + response = client.cloud.volumes.with_raw_response.create( + project_id=1, + region_id=1, + name="volume-1", + snapshot_id="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + source="snapshot", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_2(self, client: Gcore) -> None: + with client.cloud.volumes.with_streaming_response.create( + project_id=1, + region_id=1, + name="volume-1", + snapshot_id="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + source="snapshot", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_3(self, client: Gcore) -> None: + volume = client.cloud.volumes.create( + project_id=1, + region_id=1, + name="volume-1", + size=10, + source="new-volume", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_3(self, client: Gcore) -> None: + volume = client.cloud.volumes.create( + project_id=1, + region_id=1, + name="volume-1", + size=10, + source="new-volume", + attachment_tag="device-tag", + instance_id_to_attach_to="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + lifecycle_policy_ids=[1, 2], + tags={}, + type_name="standard", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_raw_response_create_overload_3(self, client: Gcore) -> None: + response = client.cloud.volumes.with_raw_response.create( + project_id=1, + region_id=1, + name="volume-1", + size=10, + source="new-volume", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_3(self, client: Gcore) -> None: + with client.cloud.volumes.with_streaming_response.create( + project_id=1, + region_id=1, + name="volume-1", + size=10, + source="new-volume", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + volume = client.cloud.volumes.update( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + volume = client.cloud.volumes.update( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + name="some_name", + tags={}, + ) + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.volumes.with_raw_response.update( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.volumes.with_streaming_response.update( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert_matches_type(Volume, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + client.cloud.volumes.with_raw_response.update( + volume_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + volume = client.cloud.volumes.list( + project_id=1, + region_id=1, + ) + assert_matches_type(SyncOffsetPage[Volume], volume, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + volume = client.cloud.volumes.list( + project_id=1, + region_id=1, + bootable=False, + cluster_id="t12345", + has_attachments=True, + id_part="726ecfcc-7fd0-4e30-a86e-7892524aa483", + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + limit=1000, + name_part="test", + offset=0, + tag_key=["key1", "key2"], + tag_key_value="tag_key_value", + ) + assert_matches_type(SyncOffsetPage[Volume], volume, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.volumes.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(SyncOffsetPage[Volume], volume, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.volumes.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert_matches_type(SyncOffsetPage[Volume], volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + volume = client.cloud.volumes.delete( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_method_delete_with_all_params(self, client: Gcore) -> None: + volume = client.cloud.volumes.delete( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + snapshots="726ecfcc-7fd0-4e30-a86e-7892524aa483,726ecfcc-7fd0-4e30-a86e-7892524aa484", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.volumes.with_raw_response.delete( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.volumes.with_streaming_response.delete( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + client.cloud.volumes.with_raw_response.delete( + volume_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_attach_to_instance(self, client: Gcore) -> None: + volume = client.cloud.volumes.attach_to_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_method_attach_to_instance_with_all_params(self, client: Gcore) -> None: + volume = client.cloud.volumes.attach_to_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + attachment_tag="boot", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_raw_response_attach_to_instance(self, client: Gcore) -> None: + response = client.cloud.volumes.with_raw_response.attach_to_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_streaming_response_attach_to_instance(self, client: Gcore) -> None: + with client.cloud.volumes.with_streaming_response.attach_to_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_attach_to_instance(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + client.cloud.volumes.with_raw_response.attach_to_instance( + volume_id="", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) + + @parametrize + def test_method_change_type(self, client: Gcore) -> None: + volume = client.cloud.volumes.change_type( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + volume_type="ssd_hiiops", + ) + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + def test_raw_response_change_type(self, client: Gcore) -> None: + response = client.cloud.volumes.with_raw_response.change_type( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + volume_type="ssd_hiiops", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + def test_streaming_response_change_type(self, client: Gcore) -> None: + with client.cloud.volumes.with_streaming_response.change_type( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + volume_type="ssd_hiiops", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert_matches_type(Volume, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_change_type(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + client.cloud.volumes.with_raw_response.change_type( + volume_id="", + project_id=1, + region_id=1, + volume_type="ssd_hiiops", + ) + + @parametrize + def test_method_detach_from_instance(self, client: Gcore) -> None: + volume = client.cloud.volumes.detach_from_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_raw_response_detach_from_instance(self, client: Gcore) -> None: + response = client.cloud.volumes.with_raw_response.detach_from_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_streaming_response_detach_from_instance(self, client: Gcore) -> None: + with client.cloud.volumes.with_streaming_response.detach_from_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_detach_from_instance(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + client.cloud.volumes.with_raw_response.detach_from_instance( + volume_id="", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + volume = client.cloud.volumes.get( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.cloud.volumes.with_raw_response.get( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.cloud.volumes.with_streaming_response.get( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert_matches_type(Volume, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + client.cloud.volumes.with_raw_response.get( + volume_id="", + project_id=1, + region_id=1, + ) + + @parametrize + def test_method_resize(self, client: Gcore) -> None: + volume = client.cloud.volumes.resize( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + size=100, + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_raw_response_resize(self, client: Gcore) -> None: + response = client.cloud.volumes.with_raw_response.resize( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + size=100, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + def test_streaming_response_resize(self, client: Gcore) -> None: + with client.cloud.volumes.with_streaming_response.resize( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + size=100, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_resize(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + client.cloud.volumes.with_raw_response.resize( + volume_id="", + project_id=1, + region_id=1, + size=100, + ) + + @parametrize + def test_method_revert_to_last_snapshot(self, client: Gcore) -> None: + volume = client.cloud.volumes.revert_to_last_snapshot( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert volume is None + + @parametrize + def test_raw_response_revert_to_last_snapshot(self, client: Gcore) -> None: + response = client.cloud.volumes.with_raw_response.revert_to_last_snapshot( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert volume is None + + @parametrize + def test_streaming_response_revert_to_last_snapshot(self, client: Gcore) -> None: + with client.cloud.volumes.with_streaming_response.revert_to_last_snapshot( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert volume is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_revert_to_last_snapshot(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + client.cloud.volumes.with_raw_response.revert_to_last_snapshot( + volume_id="", + project_id=1, + region_id=1, + ) + + +class TestAsyncVolumes: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create_overload_1(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.create( + project_id=1, + region_id=1, + image_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + name="volume-1", + size=10, + source="image", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_1(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.create( + project_id=1, + region_id=1, + image_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + name="volume-1", + size=10, + source="image", + attachment_tag="device-tag", + instance_id_to_attach_to="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + lifecycle_policy_ids=[1, 2], + tags={}, + type_name="standard", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_1(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volumes.with_raw_response.create( + project_id=1, + region_id=1, + image_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + name="volume-1", + size=10, + source="image", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_1(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volumes.with_streaming_response.create( + project_id=1, + region_id=1, + image_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + name="volume-1", + size=10, + source="image", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_2(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.create( + project_id=1, + region_id=1, + name="volume-1", + snapshot_id="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + source="snapshot", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_2(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.create( + project_id=1, + region_id=1, + name="volume-1", + snapshot_id="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + source="snapshot", + attachment_tag="device-tag", + instance_id_to_attach_to="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + lifecycle_policy_ids=[1, 2], + size=10, + tags={}, + type_name="standard", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_2(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volumes.with_raw_response.create( + project_id=1, + region_id=1, + name="volume-1", + snapshot_id="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + source="snapshot", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_2(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volumes.with_streaming_response.create( + project_id=1, + region_id=1, + name="volume-1", + snapshot_id="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + source="snapshot", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_3(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.create( + project_id=1, + region_id=1, + name="volume-1", + size=10, + source="new-volume", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_3(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.create( + project_id=1, + region_id=1, + name="volume-1", + size=10, + source="new-volume", + attachment_tag="device-tag", + instance_id_to_attach_to="88f3e0bd-ca86-4cf7-be8b-dd2988e23c2d", + lifecycle_policy_ids=[1, 2], + tags={}, + type_name="standard", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_3(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volumes.with_raw_response.create( + project_id=1, + region_id=1, + name="volume-1", + size=10, + source="new-volume", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_3(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volumes.with_streaming_response.create( + project_id=1, + region_id=1, + name="volume-1", + size=10, + source="new-volume", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.update( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.update( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + name="some_name", + tags={}, + ) + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volumes.with_raw_response.update( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = await response.parse() + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volumes.with_streaming_response.update( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert_matches_type(Volume, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + await async_client.cloud.volumes.with_raw_response.update( + volume_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.list( + project_id=1, + region_id=1, + ) + assert_matches_type(AsyncOffsetPage[Volume], volume, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.list( + project_id=1, + region_id=1, + bootable=False, + cluster_id="t12345", + has_attachments=True, + id_part="726ecfcc-7fd0-4e30-a86e-7892524aa483", + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + limit=1000, + name_part="test", + offset=0, + tag_key=["key1", "key2"], + tag_key_value="tag_key_value", + ) + assert_matches_type(AsyncOffsetPage[Volume], volume, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volumes.with_raw_response.list( + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = await response.parse() + assert_matches_type(AsyncOffsetPage[Volume], volume, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volumes.with_streaming_response.list( + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert_matches_type(AsyncOffsetPage[Volume], volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.delete( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.delete( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + snapshots="726ecfcc-7fd0-4e30-a86e-7892524aa483,726ecfcc-7fd0-4e30-a86e-7892524aa484", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volumes.with_raw_response.delete( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volumes.with_streaming_response.delete( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + await async_client.cloud.volumes.with_raw_response.delete( + volume_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_attach_to_instance(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.attach_to_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_method_attach_to_instance_with_all_params(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.attach_to_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + attachment_tag="boot", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_raw_response_attach_to_instance(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volumes.with_raw_response.attach_to_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_streaming_response_attach_to_instance(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volumes.with_streaming_response.attach_to_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_attach_to_instance(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + await async_client.cloud.volumes.with_raw_response.attach_to_instance( + volume_id="", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) + + @parametrize + async def test_method_change_type(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.change_type( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + volume_type="ssd_hiiops", + ) + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + async def test_raw_response_change_type(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volumes.with_raw_response.change_type( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + volume_type="ssd_hiiops", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = await response.parse() + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + async def test_streaming_response_change_type(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volumes.with_streaming_response.change_type( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + volume_type="ssd_hiiops", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert_matches_type(Volume, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_change_type(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + await async_client.cloud.volumes.with_raw_response.change_type( + volume_id="", + project_id=1, + region_id=1, + volume_type="ssd_hiiops", + ) + + @parametrize + async def test_method_detach_from_instance(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.detach_from_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_raw_response_detach_from_instance(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volumes.with_raw_response.detach_from_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_streaming_response_detach_from_instance(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volumes.with_streaming_response.detach_from_instance( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_detach_from_instance(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + await async_client.cloud.volumes.with_raw_response.detach_from_instance( + volume_id="", + project_id=1, + region_id=1, + instance_id="169942e0-9b53-42df-95ef-1a8b6525c2bd", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.get( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volumes.with_raw_response.get( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = await response.parse() + assert_matches_type(Volume, volume, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volumes.with_streaming_response.get( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert_matches_type(Volume, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + await async_client.cloud.volumes.with_raw_response.get( + volume_id="", + project_id=1, + region_id=1, + ) + + @parametrize + async def test_method_resize(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.resize( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + size=100, + ) + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_raw_response_resize(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volumes.with_raw_response.resize( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + size=100, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + @parametrize + async def test_streaming_response_resize(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volumes.with_streaming_response.resize( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + size=100, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert_matches_type(TaskIDList, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_resize(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + await async_client.cloud.volumes.with_raw_response.resize( + volume_id="", + project_id=1, + region_id=1, + size=100, + ) + + @parametrize + async def test_method_revert_to_last_snapshot(self, async_client: AsyncGcore) -> None: + volume = await async_client.cloud.volumes.revert_to_last_snapshot( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + assert volume is None + + @parametrize + async def test_raw_response_revert_to_last_snapshot(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.volumes.with_raw_response.revert_to_last_snapshot( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = await response.parse() + assert volume is None + + @parametrize + async def test_streaming_response_revert_to_last_snapshot(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.volumes.with_streaming_response.revert_to_last_snapshot( + volume_id="726ecfcc-7fd0-4e30-a86e-7892524aa483", + project_id=1, + region_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert volume is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_revert_to_last_snapshot(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `volume_id` but received ''"): + await async_client.cloud.volumes.with_raw_response.revert_to_last_snapshot( + volume_id="", + project_id=1, + region_id=1, + ) diff --git a/tests/api_resources/cloud/users/__init__.py b/tests/api_resources/cloud/users/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/cloud/users/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/cloud/users/test_role_assignments.py b/tests/api_resources/cloud/users/test_role_assignments.py new file mode 100644 index 00000000..e29064ca --- /dev/null +++ b/tests/api_resources/cloud/users/test_role_assignments.py @@ -0,0 +1,344 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.cloud.users import ( + RoleAssignment, + RoleAssignmentUpdatedDeleted, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRoleAssignments: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + role_assignment = client.cloud.users.role_assignments.create( + role="ClientAdministrator", + user_id=777, + ) + assert_matches_type(RoleAssignment, role_assignment, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + role_assignment = client.cloud.users.role_assignments.create( + role="ClientAdministrator", + user_id=777, + client_id=8, + project_id=None, + ) + assert_matches_type(RoleAssignment, role_assignment, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.cloud.users.role_assignments.with_raw_response.create( + role="ClientAdministrator", + user_id=777, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role_assignment = response.parse() + assert_matches_type(RoleAssignment, role_assignment, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.cloud.users.role_assignments.with_streaming_response.create( + role="ClientAdministrator", + user_id=777, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role_assignment = response.parse() + assert_matches_type(RoleAssignment, role_assignment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + role_assignment = client.cloud.users.role_assignments.update( + assignment_id=123, + role="ClientAdministrator", + user_id=777, + ) + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + role_assignment = client.cloud.users.role_assignments.update( + assignment_id=123, + role="ClientAdministrator", + user_id=777, + client_id=8, + project_id=None, + ) + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.cloud.users.role_assignments.with_raw_response.update( + assignment_id=123, + role="ClientAdministrator", + user_id=777, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role_assignment = response.parse() + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.cloud.users.role_assignments.with_streaming_response.update( + assignment_id=123, + role="ClientAdministrator", + user_id=777, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role_assignment = response.parse() + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + role_assignment = client.cloud.users.role_assignments.list() + assert_matches_type(SyncOffsetPage[RoleAssignment], role_assignment, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + role_assignment = client.cloud.users.role_assignments.list( + limit=100, + offset=0, + project_id=123, + user_id=123, + ) + assert_matches_type(SyncOffsetPage[RoleAssignment], role_assignment, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.cloud.users.role_assignments.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role_assignment = response.parse() + assert_matches_type(SyncOffsetPage[RoleAssignment], role_assignment, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.cloud.users.role_assignments.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role_assignment = response.parse() + assert_matches_type(SyncOffsetPage[RoleAssignment], role_assignment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + role_assignment = client.cloud.users.role_assignments.delete( + 123, + ) + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.cloud.users.role_assignments.with_raw_response.delete( + 123, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role_assignment = response.parse() + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.cloud.users.role_assignments.with_streaming_response.delete( + 123, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role_assignment = response.parse() + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncRoleAssignments: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + role_assignment = await async_client.cloud.users.role_assignments.create( + role="ClientAdministrator", + user_id=777, + ) + assert_matches_type(RoleAssignment, role_assignment, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + role_assignment = await async_client.cloud.users.role_assignments.create( + role="ClientAdministrator", + user_id=777, + client_id=8, + project_id=None, + ) + assert_matches_type(RoleAssignment, role_assignment, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.users.role_assignments.with_raw_response.create( + role="ClientAdministrator", + user_id=777, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role_assignment = await response.parse() + assert_matches_type(RoleAssignment, role_assignment, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.users.role_assignments.with_streaming_response.create( + role="ClientAdministrator", + user_id=777, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role_assignment = await response.parse() + assert_matches_type(RoleAssignment, role_assignment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + role_assignment = await async_client.cloud.users.role_assignments.update( + assignment_id=123, + role="ClientAdministrator", + user_id=777, + ) + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + role_assignment = await async_client.cloud.users.role_assignments.update( + assignment_id=123, + role="ClientAdministrator", + user_id=777, + client_id=8, + project_id=None, + ) + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.users.role_assignments.with_raw_response.update( + assignment_id=123, + role="ClientAdministrator", + user_id=777, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role_assignment = await response.parse() + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.users.role_assignments.with_streaming_response.update( + assignment_id=123, + role="ClientAdministrator", + user_id=777, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role_assignment = await response.parse() + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + role_assignment = await async_client.cloud.users.role_assignments.list() + assert_matches_type(AsyncOffsetPage[RoleAssignment], role_assignment, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + role_assignment = await async_client.cloud.users.role_assignments.list( + limit=100, + offset=0, + project_id=123, + user_id=123, + ) + assert_matches_type(AsyncOffsetPage[RoleAssignment], role_assignment, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.users.role_assignments.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role_assignment = await response.parse() + assert_matches_type(AsyncOffsetPage[RoleAssignment], role_assignment, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.users.role_assignments.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role_assignment = await response.parse() + assert_matches_type(AsyncOffsetPage[RoleAssignment], role_assignment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + role_assignment = await async_client.cloud.users.role_assignments.delete( + 123, + ) + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.users.role_assignments.with_raw_response.delete( + 123, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + role_assignment = await response.parse() + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.users.role_assignments.with_streaming_response.delete( + 123, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + role_assignment = await response.parse() + assert_matches_type(RoleAssignmentUpdatedDeleted, role_assignment, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/dns/__init__.py b/tests/api_resources/dns/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/dns/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/dns/pickers/__init__.py b/tests/api_resources/dns/pickers/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/dns/pickers/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/dns/pickers/test_presets.py b/tests/api_resources/dns/pickers/test_presets.py new file mode 100644 index 00000000..3622687a --- /dev/null +++ b/tests/api_resources/dns/pickers/test_presets.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.dns.pickers import PresetListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPresets: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + preset = client.dns.pickers.presets.list() + assert_matches_type(PresetListResponse, preset, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.dns.pickers.presets.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preset = response.parse() + assert_matches_type(PresetListResponse, preset, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.dns.pickers.presets.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preset = response.parse() + assert_matches_type(PresetListResponse, preset, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncPresets: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + preset = await async_client.dns.pickers.presets.list() + assert_matches_type(PresetListResponse, preset, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.pickers.presets.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preset = await response.parse() + assert_matches_type(PresetListResponse, preset, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.dns.pickers.presets.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preset = await response.parse() + assert_matches_type(PresetListResponse, preset, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/dns/test_locations.py b/tests/api_resources/dns/test_locations.py new file mode 100644 index 00000000..185d35d1 --- /dev/null +++ b/tests/api_resources/dns/test_locations.py @@ -0,0 +1,229 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.dns import ( + LocationListResponse, + LocationListRegionsResponse, + LocationListCountriesResponse, + LocationListContinentsResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestLocations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + location = client.dns.locations.list() + assert_matches_type(LocationListResponse, location, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.dns.locations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + location = response.parse() + assert_matches_type(LocationListResponse, location, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.dns.locations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + location = response.parse() + assert_matches_type(LocationListResponse, location, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_continents(self, client: Gcore) -> None: + location = client.dns.locations.list_continents() + assert_matches_type(LocationListContinentsResponse, location, path=["response"]) + + @parametrize + def test_raw_response_list_continents(self, client: Gcore) -> None: + response = client.dns.locations.with_raw_response.list_continents() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + location = response.parse() + assert_matches_type(LocationListContinentsResponse, location, path=["response"]) + + @parametrize + def test_streaming_response_list_continents(self, client: Gcore) -> None: + with client.dns.locations.with_streaming_response.list_continents() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + location = response.parse() + assert_matches_type(LocationListContinentsResponse, location, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_countries(self, client: Gcore) -> None: + location = client.dns.locations.list_countries() + assert_matches_type(LocationListCountriesResponse, location, path=["response"]) + + @parametrize + def test_raw_response_list_countries(self, client: Gcore) -> None: + response = client.dns.locations.with_raw_response.list_countries() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + location = response.parse() + assert_matches_type(LocationListCountriesResponse, location, path=["response"]) + + @parametrize + def test_streaming_response_list_countries(self, client: Gcore) -> None: + with client.dns.locations.with_streaming_response.list_countries() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + location = response.parse() + assert_matches_type(LocationListCountriesResponse, location, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_regions(self, client: Gcore) -> None: + location = client.dns.locations.list_regions() + assert_matches_type(LocationListRegionsResponse, location, path=["response"]) + + @parametrize + def test_raw_response_list_regions(self, client: Gcore) -> None: + response = client.dns.locations.with_raw_response.list_regions() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + location = response.parse() + assert_matches_type(LocationListRegionsResponse, location, path=["response"]) + + @parametrize + def test_streaming_response_list_regions(self, client: Gcore) -> None: + with client.dns.locations.with_streaming_response.list_regions() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + location = response.parse() + assert_matches_type(LocationListRegionsResponse, location, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncLocations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + location = await async_client.dns.locations.list() + assert_matches_type(LocationListResponse, location, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.locations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + location = await response.parse() + assert_matches_type(LocationListResponse, location, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.dns.locations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + location = await response.parse() + assert_matches_type(LocationListResponse, location, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_continents(self, async_client: AsyncGcore) -> None: + location = await async_client.dns.locations.list_continents() + assert_matches_type(LocationListContinentsResponse, location, path=["response"]) + + @parametrize + async def test_raw_response_list_continents(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.locations.with_raw_response.list_continents() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + location = await response.parse() + assert_matches_type(LocationListContinentsResponse, location, path=["response"]) + + @parametrize + async def test_streaming_response_list_continents(self, async_client: AsyncGcore) -> None: + async with async_client.dns.locations.with_streaming_response.list_continents() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + location = await response.parse() + assert_matches_type(LocationListContinentsResponse, location, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_countries(self, async_client: AsyncGcore) -> None: + location = await async_client.dns.locations.list_countries() + assert_matches_type(LocationListCountriesResponse, location, path=["response"]) + + @parametrize + async def test_raw_response_list_countries(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.locations.with_raw_response.list_countries() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + location = await response.parse() + assert_matches_type(LocationListCountriesResponse, location, path=["response"]) + + @parametrize + async def test_streaming_response_list_countries(self, async_client: AsyncGcore) -> None: + async with async_client.dns.locations.with_streaming_response.list_countries() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + location = await response.parse() + assert_matches_type(LocationListCountriesResponse, location, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_regions(self, async_client: AsyncGcore) -> None: + location = await async_client.dns.locations.list_regions() + assert_matches_type(LocationListRegionsResponse, location, path=["response"]) + + @parametrize + async def test_raw_response_list_regions(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.locations.with_raw_response.list_regions() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + location = await response.parse() + assert_matches_type(LocationListRegionsResponse, location, path=["response"]) + + @parametrize + async def test_streaming_response_list_regions(self, async_client: AsyncGcore) -> None: + async with async_client.dns.locations.with_streaming_response.list_regions() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + location = await response.parse() + assert_matches_type(LocationListRegionsResponse, location, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/dns/test_metrics.py b/tests/api_resources/dns/test_metrics.py new file mode 100644 index 00000000..a07fb783 --- /dev/null +++ b/tests/api_resources/dns/test_metrics.py @@ -0,0 +1,89 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMetrics: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + metric = client.dns.metrics.list() + assert_matches_type(str, metric, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + metric = client.dns.metrics.list( + client_ids=[0], + zone_names=["string"], + ) + assert_matches_type(str, metric, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.dns.metrics.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + metric = response.parse() + assert_matches_type(str, metric, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.dns.metrics.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + metric = response.parse() + assert_matches_type(str, metric, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncMetrics: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + metric = await async_client.dns.metrics.list() + assert_matches_type(str, metric, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + metric = await async_client.dns.metrics.list( + client_ids=[0], + zone_names=["string"], + ) + assert_matches_type(str, metric, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.metrics.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + metric = await response.parse() + assert_matches_type(str, metric, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.dns.metrics.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + metric = await response.parse() + assert_matches_type(str, metric, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/dns/test_network_mappings.py b/tests/api_resources/dns/test_network_mappings.py new file mode 100644 index 00000000..158a3f7b --- /dev/null +++ b/tests/api_resources/dns/test_network_mappings.py @@ -0,0 +1,519 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.dns import ( + DNSNetworkMapping, + NetworkMappingListResponse, + NetworkMappingCreateResponse, + NetworkMappingImportResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestNetworkMappings: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + network_mapping = client.dns.network_mappings.create() + assert_matches_type(NetworkMappingCreateResponse, network_mapping, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + network_mapping = client.dns.network_mappings.create( + mapping=[ + { + "cidr4": ["string"], + "cidr6": ["string"], + "tags": ["string"], + } + ], + name="name", + ) + assert_matches_type(NetworkMappingCreateResponse, network_mapping, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.dns.network_mappings.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = response.parse() + assert_matches_type(NetworkMappingCreateResponse, network_mapping, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.dns.network_mappings.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = response.parse() + assert_matches_type(NetworkMappingCreateResponse, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + network_mapping = client.dns.network_mappings.list() + assert_matches_type(NetworkMappingListResponse, network_mapping, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + network_mapping = client.dns.network_mappings.list( + limit=0, + offset=0, + order_by="order_by", + order_direction="asc", + ) + assert_matches_type(NetworkMappingListResponse, network_mapping, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.dns.network_mappings.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = response.parse() + assert_matches_type(NetworkMappingListResponse, network_mapping, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.dns.network_mappings.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = response.parse() + assert_matches_type(NetworkMappingListResponse, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + network_mapping = client.dns.network_mappings.delete( + 0, + ) + assert_matches_type(object, network_mapping, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.dns.network_mappings.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = response.parse() + assert_matches_type(object, network_mapping, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.dns.network_mappings.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = response.parse() + assert_matches_type(object, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + network_mapping = client.dns.network_mappings.get( + 0, + ) + assert_matches_type(DNSNetworkMapping, network_mapping, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.dns.network_mappings.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = response.parse() + assert_matches_type(DNSNetworkMapping, network_mapping, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.dns.network_mappings.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = response.parse() + assert_matches_type(DNSNetworkMapping, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_by_name(self, client: Gcore) -> None: + network_mapping = client.dns.network_mappings.get_by_name( + "name", + ) + assert_matches_type(DNSNetworkMapping, network_mapping, path=["response"]) + + @parametrize + def test_raw_response_get_by_name(self, client: Gcore) -> None: + response = client.dns.network_mappings.with_raw_response.get_by_name( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = response.parse() + assert_matches_type(DNSNetworkMapping, network_mapping, path=["response"]) + + @parametrize + def test_streaming_response_get_by_name(self, client: Gcore) -> None: + with client.dns.network_mappings.with_streaming_response.get_by_name( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = response.parse() + assert_matches_type(DNSNetworkMapping, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_by_name(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + client.dns.network_mappings.with_raw_response.get_by_name( + "", + ) + + @parametrize + def test_method_import(self, client: Gcore) -> None: + network_mapping = client.dns.network_mappings.import_() + assert_matches_type(NetworkMappingImportResponse, network_mapping, path=["response"]) + + @parametrize + def test_raw_response_import(self, client: Gcore) -> None: + response = client.dns.network_mappings.with_raw_response.import_() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = response.parse() + assert_matches_type(NetworkMappingImportResponse, network_mapping, path=["response"]) + + @parametrize + def test_streaming_response_import(self, client: Gcore) -> None: + with client.dns.network_mappings.with_streaming_response.import_() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = response.parse() + assert_matches_type(NetworkMappingImportResponse, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + network_mapping = client.dns.network_mappings.replace( + id=0, + ) + assert_matches_type(object, network_mapping, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + network_mapping = client.dns.network_mappings.replace( + id=0, + mapping=[ + { + "cidr4": ["string"], + "cidr6": ["string"], + "tags": ["string"], + } + ], + name="name", + ) + assert_matches_type(object, network_mapping, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.dns.network_mappings.with_raw_response.replace( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = response.parse() + assert_matches_type(object, network_mapping, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.dns.network_mappings.with_streaming_response.replace( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = response.parse() + assert_matches_type(object, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncNetworkMappings: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + network_mapping = await async_client.dns.network_mappings.create() + assert_matches_type(NetworkMappingCreateResponse, network_mapping, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + network_mapping = await async_client.dns.network_mappings.create( + mapping=[ + { + "cidr4": ["string"], + "cidr6": ["string"], + "tags": ["string"], + } + ], + name="name", + ) + assert_matches_type(NetworkMappingCreateResponse, network_mapping, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.network_mappings.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = await response.parse() + assert_matches_type(NetworkMappingCreateResponse, network_mapping, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.dns.network_mappings.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = await response.parse() + assert_matches_type(NetworkMappingCreateResponse, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + network_mapping = await async_client.dns.network_mappings.list() + assert_matches_type(NetworkMappingListResponse, network_mapping, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + network_mapping = await async_client.dns.network_mappings.list( + limit=0, + offset=0, + order_by="order_by", + order_direction="asc", + ) + assert_matches_type(NetworkMappingListResponse, network_mapping, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.network_mappings.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = await response.parse() + assert_matches_type(NetworkMappingListResponse, network_mapping, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.dns.network_mappings.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = await response.parse() + assert_matches_type(NetworkMappingListResponse, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + network_mapping = await async_client.dns.network_mappings.delete( + 0, + ) + assert_matches_type(object, network_mapping, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.network_mappings.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = await response.parse() + assert_matches_type(object, network_mapping, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.dns.network_mappings.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = await response.parse() + assert_matches_type(object, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + network_mapping = await async_client.dns.network_mappings.get( + 0, + ) + assert_matches_type(DNSNetworkMapping, network_mapping, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.network_mappings.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = await response.parse() + assert_matches_type(DNSNetworkMapping, network_mapping, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.dns.network_mappings.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = await response.parse() + assert_matches_type(DNSNetworkMapping, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_by_name(self, async_client: AsyncGcore) -> None: + network_mapping = await async_client.dns.network_mappings.get_by_name( + "name", + ) + assert_matches_type(DNSNetworkMapping, network_mapping, path=["response"]) + + @parametrize + async def test_raw_response_get_by_name(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.network_mappings.with_raw_response.get_by_name( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = await response.parse() + assert_matches_type(DNSNetworkMapping, network_mapping, path=["response"]) + + @parametrize + async def test_streaming_response_get_by_name(self, async_client: AsyncGcore) -> None: + async with async_client.dns.network_mappings.with_streaming_response.get_by_name( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = await response.parse() + assert_matches_type(DNSNetworkMapping, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_by_name(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + await async_client.dns.network_mappings.with_raw_response.get_by_name( + "", + ) + + @parametrize + async def test_method_import(self, async_client: AsyncGcore) -> None: + network_mapping = await async_client.dns.network_mappings.import_() + assert_matches_type(NetworkMappingImportResponse, network_mapping, path=["response"]) + + @parametrize + async def test_raw_response_import(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.network_mappings.with_raw_response.import_() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = await response.parse() + assert_matches_type(NetworkMappingImportResponse, network_mapping, path=["response"]) + + @parametrize + async def test_streaming_response_import(self, async_client: AsyncGcore) -> None: + async with async_client.dns.network_mappings.with_streaming_response.import_() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = await response.parse() + assert_matches_type(NetworkMappingImportResponse, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + network_mapping = await async_client.dns.network_mappings.replace( + id=0, + ) + assert_matches_type(object, network_mapping, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + network_mapping = await async_client.dns.network_mappings.replace( + id=0, + mapping=[ + { + "cidr4": ["string"], + "cidr6": ["string"], + "tags": ["string"], + } + ], + name="name", + ) + assert_matches_type(object, network_mapping, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.network_mappings.with_raw_response.replace( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + network_mapping = await response.parse() + assert_matches_type(object, network_mapping, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.dns.network_mappings.with_streaming_response.replace( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + network_mapping = await response.parse() + assert_matches_type(object, network_mapping, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/dns/test_pickers.py b/tests/api_resources/dns/test_pickers.py new file mode 100644 index 00000000..68d2d832 --- /dev/null +++ b/tests/api_resources/dns/test_pickers.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.dns import PickerListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPickers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + picker = client.dns.pickers.list() + assert_matches_type(PickerListResponse, picker, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.dns.pickers.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + picker = response.parse() + assert_matches_type(PickerListResponse, picker, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.dns.pickers.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + picker = response.parse() + assert_matches_type(PickerListResponse, picker, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncPickers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + picker = await async_client.dns.pickers.list() + assert_matches_type(PickerListResponse, picker, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.pickers.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + picker = await response.parse() + assert_matches_type(PickerListResponse, picker, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.dns.pickers.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + picker = await response.parse() + assert_matches_type(PickerListResponse, picker, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/dns/test_zones.py b/tests/api_resources/dns/test_zones.py new file mode 100644 index 00000000..cdb8d744 --- /dev/null +++ b/tests/api_resources/dns/test_zones.py @@ -0,0 +1,987 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.types.dns import ( + ZoneGetResponse, + ZoneListResponse, + ZoneCreateResponse, + ZoneExportResponse, + ZoneImportResponse, + ZoneGetStatisticsResponse, + ZoneCheckDelegationStatusResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestZones: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + zone = client.dns.zones.create( + name="example.com", + ) + assert_matches_type(ZoneCreateResponse, zone, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + zone = client.dns.zones.create( + name="example.com", + contact="contact", + enabled=True, + expiry=0, + meta={"foo": {}}, + nx_ttl=0, + primary_server="primary_server", + refresh=0, + retry=0, + serial=0, + ) + assert_matches_type(ZoneCreateResponse, zone, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.dns.zones.with_raw_response.create( + name="example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = response.parse() + assert_matches_type(ZoneCreateResponse, zone, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.dns.zones.with_streaming_response.create( + name="example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = response.parse() + assert_matches_type(ZoneCreateResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + zone = client.dns.zones.list() + assert_matches_type(ZoneListResponse, zone, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + zone = client.dns.zones.list( + id=[0], + case_sensitive=True, + client_id=[0], + dynamic=True, + enabled=True, + exact_match=True, + healthcheck=True, + iam_reseller_id=[0], + limit=0, + name=["string"], + offset=0, + order_by="order_by", + order_direction="asc", + reseller_id=[0], + status="status", + updated_at_from=parse_datetime("2019-12-27T18:11:19.117Z"), + updated_at_to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(ZoneListResponse, zone, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.dns.zones.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = response.parse() + assert_matches_type(ZoneListResponse, zone, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.dns.zones.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = response.parse() + assert_matches_type(ZoneListResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + zone = client.dns.zones.delete( + "name", + ) + assert_matches_type(object, zone, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.dns.zones.with_raw_response.delete( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = response.parse() + assert_matches_type(object, zone, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.dns.zones.with_streaming_response.delete( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = response.parse() + assert_matches_type(object, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + client.dns.zones.with_raw_response.delete( + "", + ) + + @parametrize + def test_method_check_delegation_status(self, client: Gcore) -> None: + zone = client.dns.zones.check_delegation_status( + "name", + ) + assert_matches_type(ZoneCheckDelegationStatusResponse, zone, path=["response"]) + + @parametrize + def test_raw_response_check_delegation_status(self, client: Gcore) -> None: + response = client.dns.zones.with_raw_response.check_delegation_status( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = response.parse() + assert_matches_type(ZoneCheckDelegationStatusResponse, zone, path=["response"]) + + @parametrize + def test_streaming_response_check_delegation_status(self, client: Gcore) -> None: + with client.dns.zones.with_streaming_response.check_delegation_status( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = response.parse() + assert_matches_type(ZoneCheckDelegationStatusResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_check_delegation_status(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + client.dns.zones.with_raw_response.check_delegation_status( + "", + ) + + @parametrize + def test_method_disable(self, client: Gcore) -> None: + zone = client.dns.zones.disable( + "name", + ) + assert_matches_type(object, zone, path=["response"]) + + @parametrize + def test_raw_response_disable(self, client: Gcore) -> None: + response = client.dns.zones.with_raw_response.disable( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = response.parse() + assert_matches_type(object, zone, path=["response"]) + + @parametrize + def test_streaming_response_disable(self, client: Gcore) -> None: + with client.dns.zones.with_streaming_response.disable( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = response.parse() + assert_matches_type(object, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_disable(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + client.dns.zones.with_raw_response.disable( + "", + ) + + @parametrize + def test_method_enable(self, client: Gcore) -> None: + zone = client.dns.zones.enable( + "name", + ) + assert_matches_type(object, zone, path=["response"]) + + @parametrize + def test_raw_response_enable(self, client: Gcore) -> None: + response = client.dns.zones.with_raw_response.enable( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = response.parse() + assert_matches_type(object, zone, path=["response"]) + + @parametrize + def test_streaming_response_enable(self, client: Gcore) -> None: + with client.dns.zones.with_streaming_response.enable( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = response.parse() + assert_matches_type(object, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_enable(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + client.dns.zones.with_raw_response.enable( + "", + ) + + @parametrize + def test_method_export(self, client: Gcore) -> None: + zone = client.dns.zones.export( + "zoneName", + ) + assert_matches_type(ZoneExportResponse, zone, path=["response"]) + + @parametrize + def test_raw_response_export(self, client: Gcore) -> None: + response = client.dns.zones.with_raw_response.export( + "zoneName", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = response.parse() + assert_matches_type(ZoneExportResponse, zone, path=["response"]) + + @parametrize + def test_streaming_response_export(self, client: Gcore) -> None: + with client.dns.zones.with_streaming_response.export( + "zoneName", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = response.parse() + assert_matches_type(ZoneExportResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_export(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + client.dns.zones.with_raw_response.export( + "", + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + zone = client.dns.zones.get( + "name", + ) + assert_matches_type(ZoneGetResponse, zone, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.dns.zones.with_raw_response.get( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = response.parse() + assert_matches_type(ZoneGetResponse, zone, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.dns.zones.with_streaming_response.get( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = response.parse() + assert_matches_type(ZoneGetResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + client.dns.zones.with_raw_response.get( + "", + ) + + @parametrize + def test_method_get_statistics(self, client: Gcore) -> None: + zone = client.dns.zones.get_statistics( + name="name", + ) + assert_matches_type(ZoneGetStatisticsResponse, zone, path=["response"]) + + @parametrize + def test_method_get_statistics_with_all_params(self, client: Gcore) -> None: + zone = client.dns.zones.get_statistics( + name="name", + from_=0, + granularity="granularity", + record_type="record_type", + to=0, + ) + assert_matches_type(ZoneGetStatisticsResponse, zone, path=["response"]) + + @parametrize + def test_raw_response_get_statistics(self, client: Gcore) -> None: + response = client.dns.zones.with_raw_response.get_statistics( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = response.parse() + assert_matches_type(ZoneGetStatisticsResponse, zone, path=["response"]) + + @parametrize + def test_streaming_response_get_statistics(self, client: Gcore) -> None: + with client.dns.zones.with_streaming_response.get_statistics( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = response.parse() + assert_matches_type(ZoneGetStatisticsResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_statistics(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + client.dns.zones.with_raw_response.get_statistics( + name="", + ) + + @parametrize + def test_method_import(self, client: Gcore) -> None: + zone = client.dns.zones.import_( + zone_name="zoneName", + ) + assert_matches_type(ZoneImportResponse, zone, path=["response"]) + + @parametrize + def test_method_import_with_all_params(self, client: Gcore) -> None: + zone = client.dns.zones.import_( + zone_name="zoneName", + body={}, + ) + assert_matches_type(ZoneImportResponse, zone, path=["response"]) + + @parametrize + def test_raw_response_import(self, client: Gcore) -> None: + response = client.dns.zones.with_raw_response.import_( + zone_name="zoneName", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = response.parse() + assert_matches_type(ZoneImportResponse, zone, path=["response"]) + + @parametrize + def test_streaming_response_import(self, client: Gcore) -> None: + with client.dns.zones.with_streaming_response.import_( + zone_name="zoneName", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = response.parse() + assert_matches_type(ZoneImportResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_import(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + client.dns.zones.with_raw_response.import_( + zone_name="", + ) + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + zone = client.dns.zones.replace( + path_name="name", + body_name="example.com", + ) + assert_matches_type(object, zone, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + zone = client.dns.zones.replace( + path_name="name", + body_name="example.com", + contact="contact", + enabled=True, + expiry=0, + meta={"foo": {}}, + nx_ttl=0, + primary_server="primary_server", + refresh=0, + retry=0, + serial=0, + ) + assert_matches_type(object, zone, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.dns.zones.with_raw_response.replace( + path_name="name", + body_name="example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = response.parse() + assert_matches_type(object, zone, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.dns.zones.with_streaming_response.replace( + path_name="name", + body_name="example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = response.parse() + assert_matches_type(object, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_replace(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_name` but received ''"): + client.dns.zones.with_raw_response.replace( + path_name="", + body_name="example.com", + ) + + +class TestAsyncZones: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.create( + name="example.com", + ) + assert_matches_type(ZoneCreateResponse, zone, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.create( + name="example.com", + contact="contact", + enabled=True, + expiry=0, + meta={"foo": {}}, + nx_ttl=0, + primary_server="primary_server", + refresh=0, + retry=0, + serial=0, + ) + assert_matches_type(ZoneCreateResponse, zone, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.with_raw_response.create( + name="example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = await response.parse() + assert_matches_type(ZoneCreateResponse, zone, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.with_streaming_response.create( + name="example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = await response.parse() + assert_matches_type(ZoneCreateResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.list() + assert_matches_type(ZoneListResponse, zone, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.list( + id=[0], + case_sensitive=True, + client_id=[0], + dynamic=True, + enabled=True, + exact_match=True, + healthcheck=True, + iam_reseller_id=[0], + limit=0, + name=["string"], + offset=0, + order_by="order_by", + order_direction="asc", + reseller_id=[0], + status="status", + updated_at_from=parse_datetime("2019-12-27T18:11:19.117Z"), + updated_at_to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(ZoneListResponse, zone, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = await response.parse() + assert_matches_type(ZoneListResponse, zone, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = await response.parse() + assert_matches_type(ZoneListResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.delete( + "name", + ) + assert_matches_type(object, zone, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.with_raw_response.delete( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = await response.parse() + assert_matches_type(object, zone, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.with_streaming_response.delete( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = await response.parse() + assert_matches_type(object, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + await async_client.dns.zones.with_raw_response.delete( + "", + ) + + @parametrize + async def test_method_check_delegation_status(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.check_delegation_status( + "name", + ) + assert_matches_type(ZoneCheckDelegationStatusResponse, zone, path=["response"]) + + @parametrize + async def test_raw_response_check_delegation_status(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.with_raw_response.check_delegation_status( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = await response.parse() + assert_matches_type(ZoneCheckDelegationStatusResponse, zone, path=["response"]) + + @parametrize + async def test_streaming_response_check_delegation_status(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.with_streaming_response.check_delegation_status( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = await response.parse() + assert_matches_type(ZoneCheckDelegationStatusResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_check_delegation_status(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + await async_client.dns.zones.with_raw_response.check_delegation_status( + "", + ) + + @parametrize + async def test_method_disable(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.disable( + "name", + ) + assert_matches_type(object, zone, path=["response"]) + + @parametrize + async def test_raw_response_disable(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.with_raw_response.disable( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = await response.parse() + assert_matches_type(object, zone, path=["response"]) + + @parametrize + async def test_streaming_response_disable(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.with_streaming_response.disable( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = await response.parse() + assert_matches_type(object, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_disable(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + await async_client.dns.zones.with_raw_response.disable( + "", + ) + + @parametrize + async def test_method_enable(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.enable( + "name", + ) + assert_matches_type(object, zone, path=["response"]) + + @parametrize + async def test_raw_response_enable(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.with_raw_response.enable( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = await response.parse() + assert_matches_type(object, zone, path=["response"]) + + @parametrize + async def test_streaming_response_enable(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.with_streaming_response.enable( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = await response.parse() + assert_matches_type(object, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_enable(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + await async_client.dns.zones.with_raw_response.enable( + "", + ) + + @parametrize + async def test_method_export(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.export( + "zoneName", + ) + assert_matches_type(ZoneExportResponse, zone, path=["response"]) + + @parametrize + async def test_raw_response_export(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.with_raw_response.export( + "zoneName", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = await response.parse() + assert_matches_type(ZoneExportResponse, zone, path=["response"]) + + @parametrize + async def test_streaming_response_export(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.with_streaming_response.export( + "zoneName", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = await response.parse() + assert_matches_type(ZoneExportResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_export(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + await async_client.dns.zones.with_raw_response.export( + "", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.get( + "name", + ) + assert_matches_type(ZoneGetResponse, zone, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.with_raw_response.get( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = await response.parse() + assert_matches_type(ZoneGetResponse, zone, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.with_streaming_response.get( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = await response.parse() + assert_matches_type(ZoneGetResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + await async_client.dns.zones.with_raw_response.get( + "", + ) + + @parametrize + async def test_method_get_statistics(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.get_statistics( + name="name", + ) + assert_matches_type(ZoneGetStatisticsResponse, zone, path=["response"]) + + @parametrize + async def test_method_get_statistics_with_all_params(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.get_statistics( + name="name", + from_=0, + granularity="granularity", + record_type="record_type", + to=0, + ) + assert_matches_type(ZoneGetStatisticsResponse, zone, path=["response"]) + + @parametrize + async def test_raw_response_get_statistics(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.with_raw_response.get_statistics( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = await response.parse() + assert_matches_type(ZoneGetStatisticsResponse, zone, path=["response"]) + + @parametrize + async def test_streaming_response_get_statistics(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.with_streaming_response.get_statistics( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = await response.parse() + assert_matches_type(ZoneGetStatisticsResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_statistics(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + await async_client.dns.zones.with_raw_response.get_statistics( + name="", + ) + + @parametrize + async def test_method_import(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.import_( + zone_name="zoneName", + ) + assert_matches_type(ZoneImportResponse, zone, path=["response"]) + + @parametrize + async def test_method_import_with_all_params(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.import_( + zone_name="zoneName", + body={}, + ) + assert_matches_type(ZoneImportResponse, zone, path=["response"]) + + @parametrize + async def test_raw_response_import(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.with_raw_response.import_( + zone_name="zoneName", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = await response.parse() + assert_matches_type(ZoneImportResponse, zone, path=["response"]) + + @parametrize + async def test_streaming_response_import(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.with_streaming_response.import_( + zone_name="zoneName", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = await response.parse() + assert_matches_type(ZoneImportResponse, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_import(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + await async_client.dns.zones.with_raw_response.import_( + zone_name="", + ) + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.replace( + path_name="name", + body_name="example.com", + ) + assert_matches_type(object, zone, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + zone = await async_client.dns.zones.replace( + path_name="name", + body_name="example.com", + contact="contact", + enabled=True, + expiry=0, + meta={"foo": {}}, + nx_ttl=0, + primary_server="primary_server", + refresh=0, + retry=0, + serial=0, + ) + assert_matches_type(object, zone, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.with_raw_response.replace( + path_name="name", + body_name="example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + zone = await response.parse() + assert_matches_type(object, zone, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.with_streaming_response.replace( + path_name="name", + body_name="example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + zone = await response.parse() + assert_matches_type(object, zone, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_replace(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_name` but received ''"): + await async_client.dns.zones.with_raw_response.replace( + path_name="", + body_name="example.com", + ) diff --git a/tests/api_resources/dns/zones/__init__.py b/tests/api_resources/dns/zones/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/dns/zones/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/dns/zones/test_dnssec.py b/tests/api_resources/dns/zones/test_dnssec.py new file mode 100644 index 00000000..063bb6fc --- /dev/null +++ b/tests/api_resources/dns/zones/test_dnssec.py @@ -0,0 +1,192 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.dns.zones import DnssecGetResponse, DnssecUpdateResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDnssec: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_update(self, client: Gcore) -> None: + dnssec = client.dns.zones.dnssec.update( + name="name", + ) + assert_matches_type(DnssecUpdateResponse, dnssec, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + dnssec = client.dns.zones.dnssec.update( + name="name", + enabled=True, + ) + assert_matches_type(DnssecUpdateResponse, dnssec, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.dns.zones.dnssec.with_raw_response.update( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dnssec = response.parse() + assert_matches_type(DnssecUpdateResponse, dnssec, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.dns.zones.dnssec.with_streaming_response.update( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dnssec = response.parse() + assert_matches_type(DnssecUpdateResponse, dnssec, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + client.dns.zones.dnssec.with_raw_response.update( + name="", + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + dnssec = client.dns.zones.dnssec.get( + "name", + ) + assert_matches_type(DnssecGetResponse, dnssec, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.dns.zones.dnssec.with_raw_response.get( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dnssec = response.parse() + assert_matches_type(DnssecGetResponse, dnssec, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.dns.zones.dnssec.with_streaming_response.get( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dnssec = response.parse() + assert_matches_type(DnssecGetResponse, dnssec, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + client.dns.zones.dnssec.with_raw_response.get( + "", + ) + + +class TestAsyncDnssec: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + dnssec = await async_client.dns.zones.dnssec.update( + name="name", + ) + assert_matches_type(DnssecUpdateResponse, dnssec, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + dnssec = await async_client.dns.zones.dnssec.update( + name="name", + enabled=True, + ) + assert_matches_type(DnssecUpdateResponse, dnssec, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.dnssec.with_raw_response.update( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dnssec = await response.parse() + assert_matches_type(DnssecUpdateResponse, dnssec, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.dnssec.with_streaming_response.update( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dnssec = await response.parse() + assert_matches_type(DnssecUpdateResponse, dnssec, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + await async_client.dns.zones.dnssec.with_raw_response.update( + name="", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + dnssec = await async_client.dns.zones.dnssec.get( + "name", + ) + assert_matches_type(DnssecGetResponse, dnssec, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.dnssec.with_raw_response.get( + "name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dnssec = await response.parse() + assert_matches_type(DnssecGetResponse, dnssec, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.dnssec.with_streaming_response.get( + "name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dnssec = await response.parse() + assert_matches_type(DnssecGetResponse, dnssec, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `name` but received ''"): + await async_client.dns.zones.dnssec.with_raw_response.get( + "", + ) diff --git a/tests/api_resources/dns/zones/test_rrsets.py b/tests/api_resources/dns/zones/test_rrsets.py new file mode 100644 index 00000000..5012b630 --- /dev/null +++ b/tests/api_resources/dns/zones/test_rrsets.py @@ -0,0 +1,872 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.dns.zones import ( + DNSOutputRrset, + RrsetListResponse, + RrsetGetFailoverLogsResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRrsets: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + rrset = client.dns.zones.rrsets.create( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + rrset = client.dns.zones.rrsets.create( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[ + { + "content": [{}], + "enabled": True, + "meta": {"foo": {}}, + } + ], + meta={}, + pickers=[ + { + "type": "geodns", + "limit": 0, + "strict": True, + } + ], + ttl=0, + ) + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.dns.zones.rrsets.with_raw_response.create( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rrset = response.parse() + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.dns.zones.rrsets.with_streaming_response.create( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rrset = response.parse() + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + client.dns.zones.rrsets.with_raw_response.create( + rrset_type="rrsetType", + zone_name="", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_name` but received ''"): + client.dns.zones.rrsets.with_raw_response.create( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="", + resource_records=[{"content": [{}]}], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_type` but received ''"): + client.dns.zones.rrsets.with_raw_response.create( + rrset_type="", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + rrset = client.dns.zones.rrsets.list( + zone_name="zoneName", + ) + assert_matches_type(RrsetListResponse, rrset, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + rrset = client.dns.zones.rrsets.list( + zone_name="zoneName", + limit=0, + offset=0, + order_by="order_by", + order_direction="asc", + ) + assert_matches_type(RrsetListResponse, rrset, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.dns.zones.rrsets.with_raw_response.list( + zone_name="zoneName", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rrset = response.parse() + assert_matches_type(RrsetListResponse, rrset, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.dns.zones.rrsets.with_streaming_response.list( + zone_name="zoneName", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rrset = response.parse() + assert_matches_type(RrsetListResponse, rrset, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + client.dns.zones.rrsets.with_raw_response.list( + zone_name="", + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + rrset = client.dns.zones.rrsets.delete( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) + assert_matches_type(object, rrset, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.dns.zones.rrsets.with_raw_response.delete( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rrset = response.parse() + assert_matches_type(object, rrset, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.dns.zones.rrsets.with_streaming_response.delete( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rrset = response.parse() + assert_matches_type(object, rrset, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + client.dns.zones.rrsets.with_raw_response.delete( + rrset_type="rrsetType", + zone_name="", + rrset_name="rrsetName", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_name` but received ''"): + client.dns.zones.rrsets.with_raw_response.delete( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_type` but received ''"): + client.dns.zones.rrsets.with_raw_response.delete( + rrset_type="", + zone_name="zoneName", + rrset_name="rrsetName", + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + rrset = client.dns.zones.rrsets.get( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.dns.zones.rrsets.with_raw_response.get( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rrset = response.parse() + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.dns.zones.rrsets.with_streaming_response.get( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rrset = response.parse() + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + client.dns.zones.rrsets.with_raw_response.get( + rrset_type="rrsetType", + zone_name="", + rrset_name="rrsetName", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_name` but received ''"): + client.dns.zones.rrsets.with_raw_response.get( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_type` but received ''"): + client.dns.zones.rrsets.with_raw_response.get( + rrset_type="", + zone_name="zoneName", + rrset_name="rrsetName", + ) + + @parametrize + def test_method_get_failover_logs(self, client: Gcore) -> None: + rrset = client.dns.zones.rrsets.get_failover_logs( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) + assert_matches_type(RrsetGetFailoverLogsResponse, rrset, path=["response"]) + + @parametrize + def test_method_get_failover_logs_with_all_params(self, client: Gcore) -> None: + rrset = client.dns.zones.rrsets.get_failover_logs( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + limit=0, + offset=0, + ) + assert_matches_type(RrsetGetFailoverLogsResponse, rrset, path=["response"]) + + @parametrize + def test_raw_response_get_failover_logs(self, client: Gcore) -> None: + response = client.dns.zones.rrsets.with_raw_response.get_failover_logs( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rrset = response.parse() + assert_matches_type(RrsetGetFailoverLogsResponse, rrset, path=["response"]) + + @parametrize + def test_streaming_response_get_failover_logs(self, client: Gcore) -> None: + with client.dns.zones.rrsets.with_streaming_response.get_failover_logs( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rrset = response.parse() + assert_matches_type(RrsetGetFailoverLogsResponse, rrset, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_failover_logs(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + client.dns.zones.rrsets.with_raw_response.get_failover_logs( + rrset_type="rrsetType", + zone_name="", + rrset_name="rrsetName", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_name` but received ''"): + client.dns.zones.rrsets.with_raw_response.get_failover_logs( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_type` but received ''"): + client.dns.zones.rrsets.with_raw_response.get_failover_logs( + rrset_type="", + zone_name="zoneName", + rrset_name="rrsetName", + ) + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + rrset = client.dns.zones.rrsets.replace( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + rrset = client.dns.zones.rrsets.replace( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[ + { + "content": [{}], + "enabled": True, + "meta": {"foo": {}}, + } + ], + meta={}, + pickers=[ + { + "type": "geodns", + "limit": 0, + "strict": True, + } + ], + ttl=0, + ) + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.dns.zones.rrsets.with_raw_response.replace( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rrset = response.parse() + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.dns.zones.rrsets.with_streaming_response.replace( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rrset = response.parse() + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_replace(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + client.dns.zones.rrsets.with_raw_response.replace( + rrset_type="rrsetType", + zone_name="", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_name` but received ''"): + client.dns.zones.rrsets.with_raw_response.replace( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="", + resource_records=[{"content": [{}]}], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_type` but received ''"): + client.dns.zones.rrsets.with_raw_response.replace( + rrset_type="", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + + +class TestAsyncRrsets: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + rrset = await async_client.dns.zones.rrsets.create( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + rrset = await async_client.dns.zones.rrsets.create( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[ + { + "content": [{}], + "enabled": True, + "meta": {"foo": {}}, + } + ], + meta={}, + pickers=[ + { + "type": "geodns", + "limit": 0, + "strict": True, + } + ], + ttl=0, + ) + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.rrsets.with_raw_response.create( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rrset = await response.parse() + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.rrsets.with_streaming_response.create( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rrset = await response.parse() + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.create( + rrset_type="rrsetType", + zone_name="", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_name` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.create( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="", + resource_records=[{"content": [{}]}], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_type` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.create( + rrset_type="", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + rrset = await async_client.dns.zones.rrsets.list( + zone_name="zoneName", + ) + assert_matches_type(RrsetListResponse, rrset, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + rrset = await async_client.dns.zones.rrsets.list( + zone_name="zoneName", + limit=0, + offset=0, + order_by="order_by", + order_direction="asc", + ) + assert_matches_type(RrsetListResponse, rrset, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.rrsets.with_raw_response.list( + zone_name="zoneName", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rrset = await response.parse() + assert_matches_type(RrsetListResponse, rrset, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.rrsets.with_streaming_response.list( + zone_name="zoneName", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rrset = await response.parse() + assert_matches_type(RrsetListResponse, rrset, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.list( + zone_name="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + rrset = await async_client.dns.zones.rrsets.delete( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) + assert_matches_type(object, rrset, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.rrsets.with_raw_response.delete( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rrset = await response.parse() + assert_matches_type(object, rrset, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.rrsets.with_streaming_response.delete( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rrset = await response.parse() + assert_matches_type(object, rrset, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.delete( + rrset_type="rrsetType", + zone_name="", + rrset_name="rrsetName", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_name` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.delete( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_type` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.delete( + rrset_type="", + zone_name="zoneName", + rrset_name="rrsetName", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + rrset = await async_client.dns.zones.rrsets.get( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.rrsets.with_raw_response.get( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rrset = await response.parse() + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.rrsets.with_streaming_response.get( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rrset = await response.parse() + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.get( + rrset_type="rrsetType", + zone_name="", + rrset_name="rrsetName", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_name` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.get( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_type` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.get( + rrset_type="", + zone_name="zoneName", + rrset_name="rrsetName", + ) + + @parametrize + async def test_method_get_failover_logs(self, async_client: AsyncGcore) -> None: + rrset = await async_client.dns.zones.rrsets.get_failover_logs( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) + assert_matches_type(RrsetGetFailoverLogsResponse, rrset, path=["response"]) + + @parametrize + async def test_method_get_failover_logs_with_all_params(self, async_client: AsyncGcore) -> None: + rrset = await async_client.dns.zones.rrsets.get_failover_logs( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + limit=0, + offset=0, + ) + assert_matches_type(RrsetGetFailoverLogsResponse, rrset, path=["response"]) + + @parametrize + async def test_raw_response_get_failover_logs(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.rrsets.with_raw_response.get_failover_logs( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rrset = await response.parse() + assert_matches_type(RrsetGetFailoverLogsResponse, rrset, path=["response"]) + + @parametrize + async def test_streaming_response_get_failover_logs(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.rrsets.with_streaming_response.get_failover_logs( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rrset = await response.parse() + assert_matches_type(RrsetGetFailoverLogsResponse, rrset, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_failover_logs(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.get_failover_logs( + rrset_type="rrsetType", + zone_name="", + rrset_name="rrsetName", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_name` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.get_failover_logs( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_type` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.get_failover_logs( + rrset_type="", + zone_name="zoneName", + rrset_name="rrsetName", + ) + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + rrset = await async_client.dns.zones.rrsets.replace( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + rrset = await async_client.dns.zones.rrsets.replace( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[ + { + "content": [{}], + "enabled": True, + "meta": {"foo": {}}, + } + ], + meta={}, + pickers=[ + { + "type": "geodns", + "limit": 0, + "strict": True, + } + ], + ttl=0, + ) + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.zones.rrsets.with_raw_response.replace( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + rrset = await response.parse() + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.dns.zones.rrsets.with_streaming_response.replace( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + rrset = await response.parse() + assert_matches_type(DNSOutputRrset, rrset, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_replace(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_name` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.replace( + rrset_type="rrsetType", + zone_name="", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_name` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.replace( + rrset_type="rrsetType", + zone_name="zoneName", + rrset_name="", + resource_records=[{"content": [{}]}], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `rrset_type` but received ''"): + await async_client.dns.zones.rrsets.with_raw_response.replace( + rrset_type="", + zone_name="zoneName", + rrset_name="rrsetName", + resource_records=[{"content": [{}]}], + ) diff --git a/tests/api_resources/fastedge/__init__.py b/tests/api_resources/fastedge/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/fastedge/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/fastedge/apps/__init__.py b/tests/api_resources/fastedge/apps/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/fastedge/apps/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/fastedge/apps/test_logs.py b/tests/api_resources/fastedge/apps/test_logs.py new file mode 100644 index 00000000..db4a3cc3 --- /dev/null +++ b/tests/api_resources/fastedge/apps/test_logs.py @@ -0,0 +1,118 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.pagination import SyncOffsetPageFastedgeAppLogs, AsyncOffsetPageFastedgeAppLogs +from gcore.types.fastedge.apps import Log + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestLogs: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + log = client.fastedge.apps.logs.list( + id=0, + ) + assert_matches_type(SyncOffsetPageFastedgeAppLogs[Log], log, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + log = client.fastedge.apps.logs.list( + id=0, + client_ip="192.168.1.1", + edge="edge", + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + limit=0, + offset=0, + search="search", + sort="desc", + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(SyncOffsetPageFastedgeAppLogs[Log], log, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.fastedge.apps.logs.with_raw_response.list( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + log = response.parse() + assert_matches_type(SyncOffsetPageFastedgeAppLogs[Log], log, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.fastedge.apps.logs.with_streaming_response.list( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + log = response.parse() + assert_matches_type(SyncOffsetPageFastedgeAppLogs[Log], log, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncLogs: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + log = await async_client.fastedge.apps.logs.list( + id=0, + ) + assert_matches_type(AsyncOffsetPageFastedgeAppLogs[Log], log, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + log = await async_client.fastedge.apps.logs.list( + id=0, + client_ip="192.168.1.1", + edge="edge", + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + limit=0, + offset=0, + search="search", + sort="desc", + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(AsyncOffsetPageFastedgeAppLogs[Log], log, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.apps.logs.with_raw_response.list( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + log = await response.parse() + assert_matches_type(AsyncOffsetPageFastedgeAppLogs[Log], log, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.apps.logs.with_streaming_response.list( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + log = await response.parse() + assert_matches_type(AsyncOffsetPageFastedgeAppLogs[Log], log, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/fastedge/test_apps.py b/tests/api_resources/fastedge/test_apps.py new file mode 100644 index 00000000..b2e2949b --- /dev/null +++ b/tests/api_resources/fastedge/test_apps.py @@ -0,0 +1,552 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPageFastedgeApps, AsyncOffsetPageFastedgeApps +from gcore.types.fastedge import ( + App, + AppShort, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestApps: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + app = client.fastedge.apps.create() + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + app = client.fastedge.apps.create( + binary=0, + comment="comment", + debug=True, + env={ + "var1": "value1", + "var2": "value2", + }, + log="kafka", + name="name", + rsp_headers={ + "header1": "value1", + "header2": "value2", + }, + secrets={"foo": {"id": 0}}, + status=0, + stores={"foo": {"id": 0}}, + template=0, + ) + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.fastedge.apps.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = response.parse() + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.fastedge.apps.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = response.parse() + assert_matches_type(AppShort, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + app = client.fastedge.apps.update( + id=0, + ) + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + app = client.fastedge.apps.update( + id=0, + binary=0, + comment="comment", + debug=True, + env={ + "var1": "value1", + "var2": "value2", + }, + log="kafka", + name="name", + rsp_headers={ + "header1": "value1", + "header2": "value2", + }, + secrets={"foo": {"id": 0}}, + status=0, + stores={"foo": {"id": 0}}, + template=0, + ) + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.fastedge.apps.with_raw_response.update( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = response.parse() + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.fastedge.apps.with_streaming_response.update( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = response.parse() + assert_matches_type(AppShort, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + app = client.fastedge.apps.list() + assert_matches_type(SyncOffsetPageFastedgeApps[AppShort], app, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + app = client.fastedge.apps.list( + api_type="wasi-http", + binary=0, + limit=0, + name="name", + offset=0, + ordering="name", + plan=0, + status=0, + template=0, + ) + assert_matches_type(SyncOffsetPageFastedgeApps[AppShort], app, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.fastedge.apps.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = response.parse() + assert_matches_type(SyncOffsetPageFastedgeApps[AppShort], app, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.fastedge.apps.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = response.parse() + assert_matches_type(SyncOffsetPageFastedgeApps[AppShort], app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + app = client.fastedge.apps.delete( + 0, + ) + assert app is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.fastedge.apps.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = response.parse() + assert app is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.fastedge.apps.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = response.parse() + assert app is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + app = client.fastedge.apps.get( + 0, + ) + assert_matches_type(App, app, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.fastedge.apps.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = response.parse() + assert_matches_type(App, app, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.fastedge.apps.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = response.parse() + assert_matches_type(App, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + app = client.fastedge.apps.replace( + id=0, + ) + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + app = client.fastedge.apps.replace( + id=0, + body={ + "binary": 0, + "comment": "comment", + "debug": True, + "env": { + "var1": "value1", + "var2": "value2", + }, + "log": "kafka", + "name": "name", + "rsp_headers": { + "header1": "value1", + "header2": "value2", + }, + "secrets": {"foo": {"id": 0}}, + "status": 0, + "stores": {"foo": {"id": 0}}, + "template": 0, + }, + ) + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.fastedge.apps.with_raw_response.replace( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = response.parse() + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.fastedge.apps.with_streaming_response.replace( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = response.parse() + assert_matches_type(AppShort, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncApps: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + app = await async_client.fastedge.apps.create() + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + app = await async_client.fastedge.apps.create( + binary=0, + comment="comment", + debug=True, + env={ + "var1": "value1", + "var2": "value2", + }, + log="kafka", + name="name", + rsp_headers={ + "header1": "value1", + "header2": "value2", + }, + secrets={"foo": {"id": 0}}, + status=0, + stores={"foo": {"id": 0}}, + template=0, + ) + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.apps.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = await response.parse() + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.apps.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = await response.parse() + assert_matches_type(AppShort, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + app = await async_client.fastedge.apps.update( + id=0, + ) + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + app = await async_client.fastedge.apps.update( + id=0, + binary=0, + comment="comment", + debug=True, + env={ + "var1": "value1", + "var2": "value2", + }, + log="kafka", + name="name", + rsp_headers={ + "header1": "value1", + "header2": "value2", + }, + secrets={"foo": {"id": 0}}, + status=0, + stores={"foo": {"id": 0}}, + template=0, + ) + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.apps.with_raw_response.update( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = await response.parse() + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.apps.with_streaming_response.update( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = await response.parse() + assert_matches_type(AppShort, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + app = await async_client.fastedge.apps.list() + assert_matches_type(AsyncOffsetPageFastedgeApps[AppShort], app, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + app = await async_client.fastedge.apps.list( + api_type="wasi-http", + binary=0, + limit=0, + name="name", + offset=0, + ordering="name", + plan=0, + status=0, + template=0, + ) + assert_matches_type(AsyncOffsetPageFastedgeApps[AppShort], app, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.apps.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = await response.parse() + assert_matches_type(AsyncOffsetPageFastedgeApps[AppShort], app, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.apps.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = await response.parse() + assert_matches_type(AsyncOffsetPageFastedgeApps[AppShort], app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + app = await async_client.fastedge.apps.delete( + 0, + ) + assert app is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.apps.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = await response.parse() + assert app is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.apps.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = await response.parse() + assert app is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + app = await async_client.fastedge.apps.get( + 0, + ) + assert_matches_type(App, app, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.apps.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = await response.parse() + assert_matches_type(App, app, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.apps.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = await response.parse() + assert_matches_type(App, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + app = await async_client.fastedge.apps.replace( + id=0, + ) + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + app = await async_client.fastedge.apps.replace( + id=0, + body={ + "binary": 0, + "comment": "comment", + "debug": True, + "env": { + "var1": "value1", + "var2": "value2", + }, + "log": "kafka", + "name": "name", + "rsp_headers": { + "header1": "value1", + "header2": "value2", + }, + "secrets": {"foo": {"id": 0}}, + "status": 0, + "stores": {"foo": {"id": 0}}, + "template": 0, + }, + ) + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.apps.with_raw_response.replace( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = await response.parse() + assert_matches_type(AppShort, app, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.apps.with_streaming_response.replace( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = await response.parse() + assert_matches_type(AppShort, app, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/fastedge/test_binaries.py b/tests/api_resources/fastedge/test_binaries.py new file mode 100644 index 00000000..1a0f1a95 --- /dev/null +++ b/tests/api_resources/fastedge/test_binaries.py @@ -0,0 +1,260 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.fastedge import Binary, BinaryShort, BinaryListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBinaries: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + binary = client.fastedge.binaries.create( + b"raw file contents", + ) + assert_matches_type(BinaryShort, binary, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.fastedge.binaries.with_raw_response.create( + b"raw file contents", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + binary = response.parse() + assert_matches_type(BinaryShort, binary, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.fastedge.binaries.with_streaming_response.create( + b"raw file contents", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + binary = response.parse() + assert_matches_type(BinaryShort, binary, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + binary = client.fastedge.binaries.list() + assert_matches_type(BinaryListResponse, binary, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.fastedge.binaries.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + binary = response.parse() + assert_matches_type(BinaryListResponse, binary, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.fastedge.binaries.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + binary = response.parse() + assert_matches_type(BinaryListResponse, binary, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + binary = client.fastedge.binaries.delete( + 0, + ) + assert binary is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.fastedge.binaries.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + binary = response.parse() + assert binary is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.fastedge.binaries.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + binary = response.parse() + assert binary is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + binary = client.fastedge.binaries.get( + 0, + ) + assert_matches_type(Binary, binary, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.fastedge.binaries.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + binary = response.parse() + assert_matches_type(Binary, binary, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.fastedge.binaries.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + binary = response.parse() + assert_matches_type(Binary, binary, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncBinaries: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + binary = await async_client.fastedge.binaries.create( + b"raw file contents", + ) + assert_matches_type(BinaryShort, binary, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.binaries.with_raw_response.create( + b"raw file contents", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + binary = await response.parse() + assert_matches_type(BinaryShort, binary, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.binaries.with_streaming_response.create( + b"raw file contents", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + binary = await response.parse() + assert_matches_type(BinaryShort, binary, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + binary = await async_client.fastedge.binaries.list() + assert_matches_type(BinaryListResponse, binary, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.binaries.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + binary = await response.parse() + assert_matches_type(BinaryListResponse, binary, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.binaries.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + binary = await response.parse() + assert_matches_type(BinaryListResponse, binary, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + binary = await async_client.fastedge.binaries.delete( + 0, + ) + assert binary is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.binaries.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + binary = await response.parse() + assert binary is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.binaries.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + binary = await response.parse() + assert binary is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + binary = await async_client.fastedge.binaries.get( + 0, + ) + assert_matches_type(Binary, binary, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.binaries.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + binary = await response.parse() + assert_matches_type(Binary, binary, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.binaries.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + binary = await response.parse() + assert_matches_type(Binary, binary, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/fastedge/test_kv_stores.py b/tests/api_resources/fastedge/test_kv_stores.py new file mode 100644 index 00000000..55851568 --- /dev/null +++ b/tests/api_resources/fastedge/test_kv_stores.py @@ -0,0 +1,400 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.fastedge import ( + KvStore, + KvStoreListResponse, + KvStoreCreateResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestKvStores: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + kv_store = client.fastedge.kv_stores.create( + name="name", + ) + assert_matches_type(KvStoreCreateResponse, kv_store, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + kv_store = client.fastedge.kv_stores.create( + name="name", + byod={ + "prefix": "prefix", + "url": "url", + }, + comment="comment", + ) + assert_matches_type(KvStoreCreateResponse, kv_store, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.fastedge.kv_stores.with_raw_response.create( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kv_store = response.parse() + assert_matches_type(KvStoreCreateResponse, kv_store, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.fastedge.kv_stores.with_streaming_response.create( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kv_store = response.parse() + assert_matches_type(KvStoreCreateResponse, kv_store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + kv_store = client.fastedge.kv_stores.list() + assert_matches_type(KvStoreListResponse, kv_store, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + kv_store = client.fastedge.kv_stores.list( + app_id=0, + limit=0, + offset=0, + ) + assert_matches_type(KvStoreListResponse, kv_store, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.fastedge.kv_stores.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kv_store = response.parse() + assert_matches_type(KvStoreListResponse, kv_store, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.fastedge.kv_stores.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kv_store = response.parse() + assert_matches_type(KvStoreListResponse, kv_store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + kv_store = client.fastedge.kv_stores.delete( + 0, + ) + assert kv_store is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.fastedge.kv_stores.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kv_store = response.parse() + assert kv_store is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.fastedge.kv_stores.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kv_store = response.parse() + assert kv_store is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + kv_store = client.fastedge.kv_stores.get( + 0, + ) + assert_matches_type(KvStore, kv_store, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.fastedge.kv_stores.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kv_store = response.parse() + assert_matches_type(KvStore, kv_store, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.fastedge.kv_stores.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kv_store = response.parse() + assert_matches_type(KvStore, kv_store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + kv_store = client.fastedge.kv_stores.replace( + id=0, + name="name", + ) + assert_matches_type(KvStore, kv_store, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + kv_store = client.fastedge.kv_stores.replace( + id=0, + name="name", + byod={ + "prefix": "prefix", + "url": "url", + }, + comment="comment", + ) + assert_matches_type(KvStore, kv_store, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.fastedge.kv_stores.with_raw_response.replace( + id=0, + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kv_store = response.parse() + assert_matches_type(KvStore, kv_store, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.fastedge.kv_stores.with_streaming_response.replace( + id=0, + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kv_store = response.parse() + assert_matches_type(KvStore, kv_store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncKvStores: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + kv_store = await async_client.fastedge.kv_stores.create( + name="name", + ) + assert_matches_type(KvStoreCreateResponse, kv_store, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + kv_store = await async_client.fastedge.kv_stores.create( + name="name", + byod={ + "prefix": "prefix", + "url": "url", + }, + comment="comment", + ) + assert_matches_type(KvStoreCreateResponse, kv_store, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.kv_stores.with_raw_response.create( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kv_store = await response.parse() + assert_matches_type(KvStoreCreateResponse, kv_store, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.kv_stores.with_streaming_response.create( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kv_store = await response.parse() + assert_matches_type(KvStoreCreateResponse, kv_store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + kv_store = await async_client.fastedge.kv_stores.list() + assert_matches_type(KvStoreListResponse, kv_store, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + kv_store = await async_client.fastedge.kv_stores.list( + app_id=0, + limit=0, + offset=0, + ) + assert_matches_type(KvStoreListResponse, kv_store, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.kv_stores.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kv_store = await response.parse() + assert_matches_type(KvStoreListResponse, kv_store, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.kv_stores.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kv_store = await response.parse() + assert_matches_type(KvStoreListResponse, kv_store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + kv_store = await async_client.fastedge.kv_stores.delete( + 0, + ) + assert kv_store is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.kv_stores.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kv_store = await response.parse() + assert kv_store is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.kv_stores.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kv_store = await response.parse() + assert kv_store is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + kv_store = await async_client.fastedge.kv_stores.get( + 0, + ) + assert_matches_type(KvStore, kv_store, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.kv_stores.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kv_store = await response.parse() + assert_matches_type(KvStore, kv_store, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.kv_stores.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kv_store = await response.parse() + assert_matches_type(KvStore, kv_store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + kv_store = await async_client.fastedge.kv_stores.replace( + id=0, + name="name", + ) + assert_matches_type(KvStore, kv_store, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + kv_store = await async_client.fastedge.kv_stores.replace( + id=0, + name="name", + byod={ + "prefix": "prefix", + "url": "url", + }, + comment="comment", + ) + assert_matches_type(KvStore, kv_store, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.kv_stores.with_raw_response.replace( + id=0, + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kv_store = await response.parse() + assert_matches_type(KvStore, kv_store, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.kv_stores.with_streaming_response.replace( + id=0, + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kv_store = await response.parse() + assert_matches_type(KvStore, kv_store, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/fastedge/test_secrets.py b/tests/api_resources/fastedge/test_secrets.py new file mode 100644 index 00000000..684ff5d4 --- /dev/null +++ b/tests/api_resources/fastedge/test_secrets.py @@ -0,0 +1,514 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.fastedge import ( + Secret, + SecretListResponse, + SecretCreateResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSecrets: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + secret = client.fastedge.secrets.create( + name="name", + ) + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + secret = client.fastedge.secrets.create( + name="name", + comment="comment", + secret_slots=[ + { + "slot": 0, + "value": "value", + } + ], + ) + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.fastedge.secrets.with_raw_response.create( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.fastedge.secrets.with_streaming_response.create( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + secret = client.fastedge.secrets.update( + id=0, + ) + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + secret = client.fastedge.secrets.update( + id=0, + comment="comment", + name="name", + secret_slots=[ + { + "slot": 0, + "value": "value", + } + ], + ) + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.fastedge.secrets.with_raw_response.update( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.fastedge.secrets.with_streaming_response.update( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + secret = client.fastedge.secrets.list() + assert_matches_type(SecretListResponse, secret, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + secret = client.fastedge.secrets.list( + app_id=0, + secret_name="secret_name", + ) + assert_matches_type(SecretListResponse, secret, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.fastedge.secrets.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(SecretListResponse, secret, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.fastedge.secrets.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(SecretListResponse, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + secret = client.fastedge.secrets.delete( + id=0, + ) + assert secret is None + + @parametrize + def test_method_delete_with_all_params(self, client: Gcore) -> None: + secret = client.fastedge.secrets.delete( + id=0, + force=True, + ) + assert secret is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.fastedge.secrets.with_raw_response.delete( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert secret is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.fastedge.secrets.with_streaming_response.delete( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert secret is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + secret = client.fastedge.secrets.get( + 0, + ) + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.fastedge.secrets.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.fastedge.secrets.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + secret = client.fastedge.secrets.replace( + id=0, + name="name", + ) + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + secret = client.fastedge.secrets.replace( + id=0, + name="name", + comment="comment", + secret_slots=[ + { + "slot": 0, + "value": "value", + } + ], + ) + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.fastedge.secrets.with_raw_response.replace( + id=0, + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.fastedge.secrets.with_streaming_response.replace( + id=0, + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncSecrets: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + secret = await async_client.fastedge.secrets.create( + name="name", + ) + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + secret = await async_client.fastedge.secrets.create( + name="name", + comment="comment", + secret_slots=[ + { + "slot": 0, + "value": "value", + } + ], + ) + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.secrets.with_raw_response.create( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.secrets.with_streaming_response.create( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(SecretCreateResponse, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + secret = await async_client.fastedge.secrets.update( + id=0, + ) + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + secret = await async_client.fastedge.secrets.update( + id=0, + comment="comment", + name="name", + secret_slots=[ + { + "slot": 0, + "value": "value", + } + ], + ) + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.secrets.with_raw_response.update( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.secrets.with_streaming_response.update( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + secret = await async_client.fastedge.secrets.list() + assert_matches_type(SecretListResponse, secret, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + secret = await async_client.fastedge.secrets.list( + app_id=0, + secret_name="secret_name", + ) + assert_matches_type(SecretListResponse, secret, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.secrets.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(SecretListResponse, secret, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.secrets.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(SecretListResponse, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + secret = await async_client.fastedge.secrets.delete( + id=0, + ) + assert secret is None + + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGcore) -> None: + secret = await async_client.fastedge.secrets.delete( + id=0, + force=True, + ) + assert secret is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.secrets.with_raw_response.delete( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert secret is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.secrets.with_streaming_response.delete( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert secret is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + secret = await async_client.fastedge.secrets.get( + 0, + ) + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.secrets.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.secrets.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + secret = await async_client.fastedge.secrets.replace( + id=0, + name="name", + ) + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + secret = await async_client.fastedge.secrets.replace( + id=0, + name="name", + comment="comment", + secret_slots=[ + { + "slot": 0, + "value": "value", + } + ], + ) + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.secrets.with_raw_response.replace( + id=0, + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + secret = await response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.secrets.with_streaming_response.replace( + id=0, + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + secret = await response.parse() + assert_matches_type(Secret, secret, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/fastedge/test_statistics.py b/tests/api_resources/fastedge/test_statistics.py new file mode 100644 index 00000000..71356be3 --- /dev/null +++ b/tests/api_resources/fastedge/test_statistics.py @@ -0,0 +1,220 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.types.fastedge import ( + StatisticGetCallSeriesResponse, + StatisticGetDurationSeriesResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestStatistics: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_call_series(self, client: Gcore) -> None: + statistic = client.fastedge.statistics.get_call_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(StatisticGetCallSeriesResponse, statistic, path=["response"]) + + @parametrize + def test_method_get_call_series_with_all_params(self, client: Gcore) -> None: + statistic = client.fastedge.statistics.get_call_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + id=0, + network="network", + ) + assert_matches_type(StatisticGetCallSeriesResponse, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_call_series(self, client: Gcore) -> None: + response = client.fastedge.statistics.with_raw_response.get_call_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(StatisticGetCallSeriesResponse, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_call_series(self, client: Gcore) -> None: + with client.fastedge.statistics.with_streaming_response.get_call_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(StatisticGetCallSeriesResponse, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_duration_series(self, client: Gcore) -> None: + statistic = client.fastedge.statistics.get_duration_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(StatisticGetDurationSeriesResponse, statistic, path=["response"]) + + @parametrize + def test_method_get_duration_series_with_all_params(self, client: Gcore) -> None: + statistic = client.fastedge.statistics.get_duration_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + id=0, + network="network", + ) + assert_matches_type(StatisticGetDurationSeriesResponse, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_duration_series(self, client: Gcore) -> None: + response = client.fastedge.statistics.with_raw_response.get_duration_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(StatisticGetDurationSeriesResponse, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_duration_series(self, client: Gcore) -> None: + with client.fastedge.statistics.with_streaming_response.get_duration_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(StatisticGetDurationSeriesResponse, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncStatistics: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_call_series(self, async_client: AsyncGcore) -> None: + statistic = await async_client.fastedge.statistics.get_call_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(StatisticGetCallSeriesResponse, statistic, path=["response"]) + + @parametrize + async def test_method_get_call_series_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.fastedge.statistics.get_call_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + id=0, + network="network", + ) + assert_matches_type(StatisticGetCallSeriesResponse, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_call_series(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.statistics.with_raw_response.get_call_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(StatisticGetCallSeriesResponse, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_call_series(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.statistics.with_streaming_response.get_call_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(StatisticGetCallSeriesResponse, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_duration_series(self, async_client: AsyncGcore) -> None: + statistic = await async_client.fastedge.statistics.get_duration_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(StatisticGetDurationSeriesResponse, statistic, path=["response"]) + + @parametrize + async def test_method_get_duration_series_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.fastedge.statistics.get_duration_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + id=0, + network="network", + ) + assert_matches_type(StatisticGetDurationSeriesResponse, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_duration_series(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.statistics.with_raw_response.get_duration_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(StatisticGetDurationSeriesResponse, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_duration_series(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.statistics.with_streaming_response.get_duration_series( + from_=parse_datetime("2019-12-27T18:11:19.117Z"), + step=0, + to=parse_datetime("2019-12-27T18:11:19.117Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(StatisticGetDurationSeriesResponse, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/fastedge/test_templates.py b/tests/api_resources/fastedge/test_templates.py new file mode 100644 index 00000000..3b530e74 --- /dev/null +++ b/tests/api_resources/fastedge/test_templates.py @@ -0,0 +1,554 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPageFastedgeTemplates, AsyncOffsetPageFastedgeTemplates +from gcore.types.fastedge import ( + Template, + TemplateShort, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTemplates: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + template = client.fastedge.templates.create( + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + } + ], + ) + assert_matches_type(TemplateShort, template, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + template = client.fastedge.templates.create( + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + "descr": "descr", + } + ], + long_descr="long_descr", + short_descr="short_descr", + ) + assert_matches_type(TemplateShort, template, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.fastedge.templates.with_raw_response.create( + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = response.parse() + assert_matches_type(TemplateShort, template, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.fastedge.templates.with_streaming_response.create( + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = response.parse() + assert_matches_type(TemplateShort, template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + template = client.fastedge.templates.list() + assert_matches_type(SyncOffsetPageFastedgeTemplates[TemplateShort], template, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + template = client.fastedge.templates.list( + api_type="wasi-http", + limit=0, + offset=0, + only_mine=True, + ) + assert_matches_type(SyncOffsetPageFastedgeTemplates[TemplateShort], template, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.fastedge.templates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = response.parse() + assert_matches_type(SyncOffsetPageFastedgeTemplates[TemplateShort], template, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.fastedge.templates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = response.parse() + assert_matches_type(SyncOffsetPageFastedgeTemplates[TemplateShort], template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + template = client.fastedge.templates.delete( + id=0, + ) + assert template is None + + @parametrize + def test_method_delete_with_all_params(self, client: Gcore) -> None: + template = client.fastedge.templates.delete( + id=0, + force=True, + ) + assert template is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.fastedge.templates.with_raw_response.delete( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = response.parse() + assert template is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.fastedge.templates.with_streaming_response.delete( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = response.parse() + assert template is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + template = client.fastedge.templates.get( + 0, + ) + assert_matches_type(Template, template, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.fastedge.templates.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = response.parse() + assert_matches_type(Template, template, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.fastedge.templates.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = response.parse() + assert_matches_type(Template, template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + template = client.fastedge.templates.replace( + id=0, + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + } + ], + ) + assert_matches_type(TemplateShort, template, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + template = client.fastedge.templates.replace( + id=0, + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + "descr": "descr", + } + ], + long_descr="long_descr", + short_descr="short_descr", + ) + assert_matches_type(TemplateShort, template, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.fastedge.templates.with_raw_response.replace( + id=0, + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = response.parse() + assert_matches_type(TemplateShort, template, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.fastedge.templates.with_streaming_response.replace( + id=0, + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = response.parse() + assert_matches_type(TemplateShort, template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncTemplates: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + template = await async_client.fastedge.templates.create( + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + } + ], + ) + assert_matches_type(TemplateShort, template, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + template = await async_client.fastedge.templates.create( + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + "descr": "descr", + } + ], + long_descr="long_descr", + short_descr="short_descr", + ) + assert_matches_type(TemplateShort, template, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.templates.with_raw_response.create( + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = await response.parse() + assert_matches_type(TemplateShort, template, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.templates.with_streaming_response.create( + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = await response.parse() + assert_matches_type(TemplateShort, template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + template = await async_client.fastedge.templates.list() + assert_matches_type(AsyncOffsetPageFastedgeTemplates[TemplateShort], template, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + template = await async_client.fastedge.templates.list( + api_type="wasi-http", + limit=0, + offset=0, + only_mine=True, + ) + assert_matches_type(AsyncOffsetPageFastedgeTemplates[TemplateShort], template, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.templates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = await response.parse() + assert_matches_type(AsyncOffsetPageFastedgeTemplates[TemplateShort], template, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.templates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = await response.parse() + assert_matches_type(AsyncOffsetPageFastedgeTemplates[TemplateShort], template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + template = await async_client.fastedge.templates.delete( + id=0, + ) + assert template is None + + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncGcore) -> None: + template = await async_client.fastedge.templates.delete( + id=0, + force=True, + ) + assert template is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.templates.with_raw_response.delete( + id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = await response.parse() + assert template is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.templates.with_streaming_response.delete( + id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = await response.parse() + assert template is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + template = await async_client.fastedge.templates.get( + 0, + ) + assert_matches_type(Template, template, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.templates.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = await response.parse() + assert_matches_type(Template, template, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.templates.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = await response.parse() + assert_matches_type(Template, template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + template = await async_client.fastedge.templates.replace( + id=0, + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + } + ], + ) + assert_matches_type(TemplateShort, template, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + template = await async_client.fastedge.templates.replace( + id=0, + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + "descr": "descr", + } + ], + long_descr="long_descr", + short_descr="short_descr", + ) + assert_matches_type(TemplateShort, template, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.templates.with_raw_response.replace( + id=0, + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + template = await response.parse() + assert_matches_type(TemplateShort, template, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.templates.with_streaming_response.replace( + id=0, + binary_id=0, + name="name", + owned=True, + params=[ + { + "data_type": "string", + "mandatory": True, + "name": "name", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + template = await response.parse() + assert_matches_type(TemplateShort, template, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/iam/__init__.py b/tests/api_resources/iam/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/iam/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/iam/test_api_tokens.py b/tests/api_resources/iam/test_api_tokens.py new file mode 100644 index 00000000..a524f1db --- /dev/null +++ b/tests/api_resources/iam/test_api_tokens.py @@ -0,0 +1,356 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.iam import APIToken, APITokenList, APITokenCreated + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAPITokens: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + api_token = client.iam.api_tokens.create( + client_id=0, + client_user={}, + exp_date="2021-01-01 12:00:00+00:00", + name="My token", + ) + assert_matches_type(APITokenCreated, api_token, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + api_token = client.iam.api_tokens.create( + client_id=0, + client_user={ + "role": { + "id": 1, + "name": "Administrators", + } + }, + exp_date="2021-01-01 12:00:00+00:00", + name="My token", + description="It's my token", + ) + assert_matches_type(APITokenCreated, api_token, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.iam.api_tokens.with_raw_response.create( + client_id=0, + client_user={}, + exp_date="2021-01-01 12:00:00+00:00", + name="My token", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_token = response.parse() + assert_matches_type(APITokenCreated, api_token, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.iam.api_tokens.with_streaming_response.create( + client_id=0, + client_user={}, + exp_date="2021-01-01 12:00:00+00:00", + name="My token", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_token = response.parse() + assert_matches_type(APITokenCreated, api_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + api_token = client.iam.api_tokens.list( + client_id=0, + ) + assert_matches_type(APITokenList, api_token, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + api_token = client.iam.api_tokens.list( + client_id=0, + deleted=True, + issued_by=0, + not_issued_by=0, + role="role", + ) + assert_matches_type(APITokenList, api_token, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.iam.api_tokens.with_raw_response.list( + client_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_token = response.parse() + assert_matches_type(APITokenList, api_token, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.iam.api_tokens.with_streaming_response.list( + client_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_token = response.parse() + assert_matches_type(APITokenList, api_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + api_token = client.iam.api_tokens.delete( + token_id=0, + client_id=0, + ) + assert api_token is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.iam.api_tokens.with_raw_response.delete( + token_id=0, + client_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_token = response.parse() + assert api_token is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.iam.api_tokens.with_streaming_response.delete( + token_id=0, + client_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_token = response.parse() + assert api_token is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + api_token = client.iam.api_tokens.get( + token_id=0, + client_id=0, + ) + assert_matches_type(APIToken, api_token, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.iam.api_tokens.with_raw_response.get( + token_id=0, + client_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_token = response.parse() + assert_matches_type(APIToken, api_token, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.iam.api_tokens.with_streaming_response.get( + token_id=0, + client_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_token = response.parse() + assert_matches_type(APIToken, api_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAPITokens: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + api_token = await async_client.iam.api_tokens.create( + client_id=0, + client_user={}, + exp_date="2021-01-01 12:00:00+00:00", + name="My token", + ) + assert_matches_type(APITokenCreated, api_token, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + api_token = await async_client.iam.api_tokens.create( + client_id=0, + client_user={ + "role": { + "id": 1, + "name": "Administrators", + } + }, + exp_date="2021-01-01 12:00:00+00:00", + name="My token", + description="It's my token", + ) + assert_matches_type(APITokenCreated, api_token, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.iam.api_tokens.with_raw_response.create( + client_id=0, + client_user={}, + exp_date="2021-01-01 12:00:00+00:00", + name="My token", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_token = await response.parse() + assert_matches_type(APITokenCreated, api_token, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.iam.api_tokens.with_streaming_response.create( + client_id=0, + client_user={}, + exp_date="2021-01-01 12:00:00+00:00", + name="My token", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_token = await response.parse() + assert_matches_type(APITokenCreated, api_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + api_token = await async_client.iam.api_tokens.list( + client_id=0, + ) + assert_matches_type(APITokenList, api_token, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + api_token = await async_client.iam.api_tokens.list( + client_id=0, + deleted=True, + issued_by=0, + not_issued_by=0, + role="role", + ) + assert_matches_type(APITokenList, api_token, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.iam.api_tokens.with_raw_response.list( + client_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_token = await response.parse() + assert_matches_type(APITokenList, api_token, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.iam.api_tokens.with_streaming_response.list( + client_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_token = await response.parse() + assert_matches_type(APITokenList, api_token, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + api_token = await async_client.iam.api_tokens.delete( + token_id=0, + client_id=0, + ) + assert api_token is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.iam.api_tokens.with_raw_response.delete( + token_id=0, + client_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_token = await response.parse() + assert api_token is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.iam.api_tokens.with_streaming_response.delete( + token_id=0, + client_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_token = await response.parse() + assert api_token is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + api_token = await async_client.iam.api_tokens.get( + token_id=0, + client_id=0, + ) + assert_matches_type(APIToken, api_token, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.iam.api_tokens.with_raw_response.get( + token_id=0, + client_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_token = await response.parse() + assert_matches_type(APIToken, api_token, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.iam.api_tokens.with_streaming_response.get( + token_id=0, + client_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_token = await response.parse() + assert_matches_type(APIToken, api_token, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/iam/test_users.py b/tests/api_resources/iam/test_users.py new file mode 100644 index 00000000..72116b06 --- /dev/null +++ b/tests/api_resources/iam/test_users.py @@ -0,0 +1,420 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.iam import ( + User, + UserInvite, + UserUpdated, + UserDetailed, +) +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestUsers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_update(self, client: Gcore) -> None: + user = client.iam.users.update( + user_id=0, + auth_types=["password"], + email="dev@stainless.com", + lang="de", + name="name", + phone="phone", + ) + assert_matches_type(UserUpdated, user, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.iam.users.with_raw_response.update( + user_id=0, + auth_types=["password"], + email="dev@stainless.com", + lang="de", + name="name", + phone="phone", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserUpdated, user, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.iam.users.with_streaming_response.update( + user_id=0, + auth_types=["password"], + email="dev@stainless.com", + lang="de", + name="name", + phone="phone", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(UserUpdated, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + user = client.iam.users.list() + assert_matches_type(SyncOffsetPage[User], user, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + user = client.iam.users.list( + limit=0, + offset=0, + ) + assert_matches_type(SyncOffsetPage[User], user, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.iam.users.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(SyncOffsetPage[User], user, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.iam.users.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(SyncOffsetPage[User], user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + user = client.iam.users.delete( + user_id=0, + client_id=0, + ) + assert user is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.iam.users.with_raw_response.delete( + user_id=0, + client_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert user is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.iam.users.with_streaming_response.delete( + user_id=0, + client_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert user is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + user = client.iam.users.get( + 0, + ) + assert_matches_type(UserDetailed, user, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.iam.users.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserDetailed, user, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.iam.users.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(UserDetailed, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_invite(self, client: Gcore) -> None: + user = client.iam.users.invite( + client_id=0, + email="dev@stainless.com", + user_role={}, + ) + assert_matches_type(UserInvite, user, path=["response"]) + + @parametrize + def test_method_invite_with_all_params(self, client: Gcore) -> None: + user = client.iam.users.invite( + client_id=0, + email="dev@stainless.com", + user_role={ + "id": 1, + "name": "Administrators", + }, + lang="de", + name="name", + ) + assert_matches_type(UserInvite, user, path=["response"]) + + @parametrize + def test_raw_response_invite(self, client: Gcore) -> None: + response = client.iam.users.with_raw_response.invite( + client_id=0, + email="dev@stainless.com", + user_role={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(UserInvite, user, path=["response"]) + + @parametrize + def test_streaming_response_invite(self, client: Gcore) -> None: + with client.iam.users.with_streaming_response.invite( + client_id=0, + email="dev@stainless.com", + user_role={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(UserInvite, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncUsers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + user = await async_client.iam.users.update( + user_id=0, + auth_types=["password"], + email="dev@stainless.com", + lang="de", + name="name", + phone="phone", + ) + assert_matches_type(UserUpdated, user, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.iam.users.with_raw_response.update( + user_id=0, + auth_types=["password"], + email="dev@stainless.com", + lang="de", + name="name", + phone="phone", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert_matches_type(UserUpdated, user, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.iam.users.with_streaming_response.update( + user_id=0, + auth_types=["password"], + email="dev@stainless.com", + lang="de", + name="name", + phone="phone", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(UserUpdated, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + user = await async_client.iam.users.list() + assert_matches_type(AsyncOffsetPage[User], user, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + user = await async_client.iam.users.list( + limit=0, + offset=0, + ) + assert_matches_type(AsyncOffsetPage[User], user, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.iam.users.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert_matches_type(AsyncOffsetPage[User], user, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.iam.users.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(AsyncOffsetPage[User], user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + user = await async_client.iam.users.delete( + user_id=0, + client_id=0, + ) + assert user is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.iam.users.with_raw_response.delete( + user_id=0, + client_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert user is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.iam.users.with_streaming_response.delete( + user_id=0, + client_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert user is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + user = await async_client.iam.users.get( + 0, + ) + assert_matches_type(UserDetailed, user, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.iam.users.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert_matches_type(UserDetailed, user, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.iam.users.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(UserDetailed, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_invite(self, async_client: AsyncGcore) -> None: + user = await async_client.iam.users.invite( + client_id=0, + email="dev@stainless.com", + user_role={}, + ) + assert_matches_type(UserInvite, user, path=["response"]) + + @parametrize + async def test_method_invite_with_all_params(self, async_client: AsyncGcore) -> None: + user = await async_client.iam.users.invite( + client_id=0, + email="dev@stainless.com", + user_role={ + "id": 1, + "name": "Administrators", + }, + lang="de", + name="name", + ) + assert_matches_type(UserInvite, user, path=["response"]) + + @parametrize + async def test_raw_response_invite(self, async_client: AsyncGcore) -> None: + response = await async_client.iam.users.with_raw_response.invite( + client_id=0, + email="dev@stainless.com", + user_role={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert_matches_type(UserInvite, user, path=["response"]) + + @parametrize + async def test_streaming_response_invite(self, async_client: AsyncGcore) -> None: + async with async_client.iam.users.with_streaming_response.invite( + client_id=0, + email="dev@stainless.com", + user_role={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(UserInvite, user, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/security/__init__.py b/tests/api_resources/security/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/security/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/security/test_bgp_announces.py b/tests/api_resources/security/test_bgp_announces.py new file mode 100644 index 00000000..8907ce2f --- /dev/null +++ b/tests/api_resources/security/test_bgp_announces.py @@ -0,0 +1,178 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.security import BgpAnnounceListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBgpAnnounces: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + bgp_announce = client.security.bgp_announces.list() + assert_matches_type(BgpAnnounceListResponse, bgp_announce, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + bgp_announce = client.security.bgp_announces.list( + announced=True, + origin="STATIC", + site="x", + ) + assert_matches_type(BgpAnnounceListResponse, bgp_announce, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.security.bgp_announces.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bgp_announce = response.parse() + assert_matches_type(BgpAnnounceListResponse, bgp_announce, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.security.bgp_announces.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bgp_announce = response.parse() + assert_matches_type(BgpAnnounceListResponse, bgp_announce, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_toggle(self, client: Gcore) -> None: + bgp_announce = client.security.bgp_announces.toggle( + announce="192.9.9.1/32", + enabled=True, + ) + assert_matches_type(object, bgp_announce, path=["response"]) + + @parametrize + def test_method_toggle_with_all_params(self, client: Gcore) -> None: + bgp_announce = client.security.bgp_announces.toggle( + announce="192.9.9.1/32", + enabled=True, + client_id=0, + ) + assert_matches_type(object, bgp_announce, path=["response"]) + + @parametrize + def test_raw_response_toggle(self, client: Gcore) -> None: + response = client.security.bgp_announces.with_raw_response.toggle( + announce="192.9.9.1/32", + enabled=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bgp_announce = response.parse() + assert_matches_type(object, bgp_announce, path=["response"]) + + @parametrize + def test_streaming_response_toggle(self, client: Gcore) -> None: + with client.security.bgp_announces.with_streaming_response.toggle( + announce="192.9.9.1/32", + enabled=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bgp_announce = response.parse() + assert_matches_type(object, bgp_announce, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncBgpAnnounces: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + bgp_announce = await async_client.security.bgp_announces.list() + assert_matches_type(BgpAnnounceListResponse, bgp_announce, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + bgp_announce = await async_client.security.bgp_announces.list( + announced=True, + origin="STATIC", + site="x", + ) + assert_matches_type(BgpAnnounceListResponse, bgp_announce, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.security.bgp_announces.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bgp_announce = await response.parse() + assert_matches_type(BgpAnnounceListResponse, bgp_announce, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.security.bgp_announces.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bgp_announce = await response.parse() + assert_matches_type(BgpAnnounceListResponse, bgp_announce, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_toggle(self, async_client: AsyncGcore) -> None: + bgp_announce = await async_client.security.bgp_announces.toggle( + announce="192.9.9.1/32", + enabled=True, + ) + assert_matches_type(object, bgp_announce, path=["response"]) + + @parametrize + async def test_method_toggle_with_all_params(self, async_client: AsyncGcore) -> None: + bgp_announce = await async_client.security.bgp_announces.toggle( + announce="192.9.9.1/32", + enabled=True, + client_id=0, + ) + assert_matches_type(object, bgp_announce, path=["response"]) + + @parametrize + async def test_raw_response_toggle(self, async_client: AsyncGcore) -> None: + response = await async_client.security.bgp_announces.with_raw_response.toggle( + announce="192.9.9.1/32", + enabled=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bgp_announce = await response.parse() + assert_matches_type(object, bgp_announce, path=["response"]) + + @parametrize + async def test_streaming_response_toggle(self, async_client: AsyncGcore) -> None: + async with async_client.security.bgp_announces.with_streaming_response.toggle( + announce="192.9.9.1/32", + enabled=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bgp_announce = await response.parse() + assert_matches_type(object, bgp_announce, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/security/test_events.py b/tests/api_resources/security/test_events.py new file mode 100644 index 00000000..650de2cf --- /dev/null +++ b/tests/api_resources/security/test_events.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.security import ClientView + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestEvents: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + event = client.security.events.list() + assert_matches_type(SyncOffsetPage[ClientView], event, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + event = client.security.events.list( + alert_type="ddos_alert", + date_from=parse_datetime("2019-12-27T18:11:19.117Z"), + date_to=parse_datetime("2019-12-27T18:11:19.117Z"), + limit=1, + offset=0, + ordering="attack_start_time", + targeted_ip_addresses="targeted_ip_addresses", + ) + assert_matches_type(SyncOffsetPage[ClientView], event, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.security.events.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + event = response.parse() + assert_matches_type(SyncOffsetPage[ClientView], event, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.security.events.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + event = response.parse() + assert_matches_type(SyncOffsetPage[ClientView], event, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncEvents: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + event = await async_client.security.events.list() + assert_matches_type(AsyncOffsetPage[ClientView], event, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + event = await async_client.security.events.list( + alert_type="ddos_alert", + date_from=parse_datetime("2019-12-27T18:11:19.117Z"), + date_to=parse_datetime("2019-12-27T18:11:19.117Z"), + limit=1, + offset=0, + ordering="attack_start_time", + targeted_ip_addresses="targeted_ip_addresses", + ) + assert_matches_type(AsyncOffsetPage[ClientView], event, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.security.events.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + event = await response.parse() + assert_matches_type(AsyncOffsetPage[ClientView], event, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.security.events.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + event = await response.parse() + assert_matches_type(AsyncOffsetPage[ClientView], event, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/security/test_profile_templates.py b/tests/api_resources/security/test_profile_templates.py new file mode 100644 index 00000000..7df4918f --- /dev/null +++ b/tests/api_resources/security/test_profile_templates.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.security import ProfileTemplateListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestProfileTemplates: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + profile_template = client.security.profile_templates.list() + assert_matches_type(ProfileTemplateListResponse, profile_template, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.security.profile_templates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile_template = response.parse() + assert_matches_type(ProfileTemplateListResponse, profile_template, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.security.profile_templates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile_template = response.parse() + assert_matches_type(ProfileTemplateListResponse, profile_template, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncProfileTemplates: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + profile_template = await async_client.security.profile_templates.list() + assert_matches_type(ProfileTemplateListResponse, profile_template, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.security.profile_templates.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile_template = await response.parse() + assert_matches_type(ProfileTemplateListResponse, profile_template, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.security.profile_templates.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile_template = await response.parse() + assert_matches_type(ProfileTemplateListResponse, profile_template, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/security/test_profiles.py b/tests/api_resources/security/test_profiles.py new file mode 100644 index 00000000..38fdfe70 --- /dev/null +++ b/tests/api_resources/security/test_profiles.py @@ -0,0 +1,537 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.security import ( + ClientProfile, + ProfileListResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestProfiles: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + profile = client.security.profiles.create( + fields=[{"base_field": 1}], + profile_template=1, + site="GNC", + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + profile = client.security.profiles.create( + fields=[ + { + "base_field": 1, + "field_value": {}, + } + ], + profile_template=1, + site="GNC", + ip_address="123.43.2.10", + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.security.profiles.with_raw_response.create( + fields=[{"base_field": 1}], + profile_template=1, + site="GNC", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.security.profiles.with_streaming_response.create( + fields=[{"base_field": 1}], + profile_template=1, + site="GNC", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + profile = client.security.profiles.list() + assert_matches_type(ProfileListResponse, profile, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + profile = client.security.profiles.list( + exclude_empty_address=True, + include_deleted=True, + ip_address="ip_address", + site="ED", + ) + assert_matches_type(ProfileListResponse, profile, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.security.profiles.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = response.parse() + assert_matches_type(ProfileListResponse, profile, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.security.profiles.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = response.parse() + assert_matches_type(ProfileListResponse, profile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + profile = client.security.profiles.delete( + 0, + ) + assert profile is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.security.profiles.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = response.parse() + assert profile is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.security.profiles.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = response.parse() + assert profile is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + profile = client.security.profiles.get( + 0, + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.security.profiles.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.security.profiles.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_recreate(self, client: Gcore) -> None: + profile = client.security.profiles.recreate( + id=0, + fields=[{"base_field": 1}], + profile_template=1, + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + def test_method_recreate_with_all_params(self, client: Gcore) -> None: + profile = client.security.profiles.recreate( + id=0, + fields=[ + { + "base_field": 1, + "field_value": {}, + } + ], + profile_template=1, + ip_address="ip_address", + site="ED", + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + def test_raw_response_recreate(self, client: Gcore) -> None: + response = client.security.profiles.with_raw_response.recreate( + id=0, + fields=[{"base_field": 1}], + profile_template=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + def test_streaming_response_recreate(self, client: Gcore) -> None: + with client.security.profiles.with_streaming_response.recreate( + id=0, + fields=[{"base_field": 1}], + profile_template=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + profile = client.security.profiles.replace( + id=0, + fields=[{"base_field": 1}], + profile_template=1, + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + def test_method_replace_with_all_params(self, client: Gcore) -> None: + profile = client.security.profiles.replace( + id=0, + fields=[ + { + "base_field": 1, + "field_value": {}, + } + ], + profile_template=1, + ip_address="ip_address", + site="ED", + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.security.profiles.with_raw_response.replace( + id=0, + fields=[{"base_field": 1}], + profile_template=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.security.profiles.with_streaming_response.replace( + id=0, + fields=[{"base_field": 1}], + profile_template=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncProfiles: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + profile = await async_client.security.profiles.create( + fields=[{"base_field": 1}], + profile_template=1, + site="GNC", + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + profile = await async_client.security.profiles.create( + fields=[ + { + "base_field": 1, + "field_value": {}, + } + ], + profile_template=1, + site="GNC", + ip_address="123.43.2.10", + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.security.profiles.with_raw_response.create( + fields=[{"base_field": 1}], + profile_template=1, + site="GNC", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = await response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.security.profiles.with_streaming_response.create( + fields=[{"base_field": 1}], + profile_template=1, + site="GNC", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = await response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + profile = await async_client.security.profiles.list() + assert_matches_type(ProfileListResponse, profile, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + profile = await async_client.security.profiles.list( + exclude_empty_address=True, + include_deleted=True, + ip_address="ip_address", + site="ED", + ) + assert_matches_type(ProfileListResponse, profile, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.security.profiles.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = await response.parse() + assert_matches_type(ProfileListResponse, profile, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.security.profiles.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = await response.parse() + assert_matches_type(ProfileListResponse, profile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + profile = await async_client.security.profiles.delete( + 0, + ) + assert profile is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.security.profiles.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = await response.parse() + assert profile is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.security.profiles.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = await response.parse() + assert profile is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + profile = await async_client.security.profiles.get( + 0, + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.security.profiles.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = await response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.security.profiles.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = await response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_recreate(self, async_client: AsyncGcore) -> None: + profile = await async_client.security.profiles.recreate( + id=0, + fields=[{"base_field": 1}], + profile_template=1, + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + async def test_method_recreate_with_all_params(self, async_client: AsyncGcore) -> None: + profile = await async_client.security.profiles.recreate( + id=0, + fields=[ + { + "base_field": 1, + "field_value": {}, + } + ], + profile_template=1, + ip_address="ip_address", + site="ED", + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + async def test_raw_response_recreate(self, async_client: AsyncGcore) -> None: + response = await async_client.security.profiles.with_raw_response.recreate( + id=0, + fields=[{"base_field": 1}], + profile_template=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = await response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + async def test_streaming_response_recreate(self, async_client: AsyncGcore) -> None: + async with async_client.security.profiles.with_streaming_response.recreate( + id=0, + fields=[{"base_field": 1}], + profile_template=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = await response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + profile = await async_client.security.profiles.replace( + id=0, + fields=[{"base_field": 1}], + profile_template=1, + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> None: + profile = await async_client.security.profiles.replace( + id=0, + fields=[ + { + "base_field": 1, + "field_value": {}, + } + ], + profile_template=1, + ip_address="ip_address", + site="ED", + ) + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.security.profiles.with_raw_response.replace( + id=0, + fields=[{"base_field": 1}], + profile_template=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = await response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.security.profiles.with_streaming_response.replace( + id=0, + fields=[{"base_field": 1}], + profile_template=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = await response.parse() + assert_matches_type(ClientProfile, profile, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/storage/__init__.py b/tests/api_resources/storage/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/storage/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/storage/buckets/__init__.py b/tests/api_resources/storage/buckets/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/storage/buckets/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/storage/buckets/test_cors.py b/tests/api_resources/storage/buckets/test_cors.py new file mode 100644 index 00000000..d9bc87a6 --- /dev/null +++ b/tests/api_resources/storage/buckets/test_cors.py @@ -0,0 +1,210 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.storage.buckets import BucketCors + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCors: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + cor = client.storage.buckets.cors.create( + bucket_name="bucket_name", + storage_id=0, + ) + assert cor is None + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + cor = client.storage.buckets.cors.create( + bucket_name="bucket_name", + storage_id=0, + allowed_origins=["https://example.com", "https://app.example.com", "*"], + ) + assert cor is None + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.storage.buckets.cors.with_raw_response.create( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cor = response.parse() + assert cor is None + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.storage.buckets.cors.with_streaming_response.create( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cor = response.parse() + assert cor is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + client.storage.buckets.cors.with_raw_response.create( + bucket_name="", + storage_id=0, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + cor = client.storage.buckets.cors.get( + bucket_name="bucket_name", + storage_id=0, + ) + assert_matches_type(BucketCors, cor, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.storage.buckets.cors.with_raw_response.get( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cor = response.parse() + assert_matches_type(BucketCors, cor, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.storage.buckets.cors.with_streaming_response.get( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cor = response.parse() + assert_matches_type(BucketCors, cor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + client.storage.buckets.cors.with_raw_response.get( + bucket_name="", + storage_id=0, + ) + + +class TestAsyncCors: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + cor = await async_client.storage.buckets.cors.create( + bucket_name="bucket_name", + storage_id=0, + ) + assert cor is None + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + cor = await async_client.storage.buckets.cors.create( + bucket_name="bucket_name", + storage_id=0, + allowed_origins=["https://example.com", "https://app.example.com", "*"], + ) + assert cor is None + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.buckets.cors.with_raw_response.create( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cor = await response.parse() + assert cor is None + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.storage.buckets.cors.with_streaming_response.create( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cor = await response.parse() + assert cor is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + await async_client.storage.buckets.cors.with_raw_response.create( + bucket_name="", + storage_id=0, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + cor = await async_client.storage.buckets.cors.get( + bucket_name="bucket_name", + storage_id=0, + ) + assert_matches_type(BucketCors, cor, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.buckets.cors.with_raw_response.get( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cor = await response.parse() + assert_matches_type(BucketCors, cor, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.storage.buckets.cors.with_streaming_response.get( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cor = await response.parse() + assert_matches_type(BucketCors, cor, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + await async_client.storage.buckets.cors.with_raw_response.get( + bucket_name="", + storage_id=0, + ) diff --git a/tests/api_resources/storage/buckets/test_lifecycle.py b/tests/api_resources/storage/buckets/test_lifecycle.py new file mode 100644 index 00000000..52e01c12 --- /dev/null +++ b/tests/api_resources/storage/buckets/test_lifecycle.py @@ -0,0 +1,208 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestLifecycle: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + lifecycle = client.storage.buckets.lifecycle.create( + bucket_name="bucket_name", + storage_id=0, + ) + assert lifecycle is None + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + lifecycle = client.storage.buckets.lifecycle.create( + bucket_name="bucket_name", + storage_id=0, + expiration_days=30, + ) + assert lifecycle is None + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.storage.buckets.lifecycle.with_raw_response.create( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + lifecycle = response.parse() + assert lifecycle is None + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.storage.buckets.lifecycle.with_streaming_response.create( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + lifecycle = response.parse() + assert lifecycle is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + client.storage.buckets.lifecycle.with_raw_response.create( + bucket_name="", + storage_id=0, + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + lifecycle = client.storage.buckets.lifecycle.delete( + bucket_name="bucket_name", + storage_id=0, + ) + assert lifecycle is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.storage.buckets.lifecycle.with_raw_response.delete( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + lifecycle = response.parse() + assert lifecycle is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.storage.buckets.lifecycle.with_streaming_response.delete( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + lifecycle = response.parse() + assert lifecycle is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + client.storage.buckets.lifecycle.with_raw_response.delete( + bucket_name="", + storage_id=0, + ) + + +class TestAsyncLifecycle: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + lifecycle = await async_client.storage.buckets.lifecycle.create( + bucket_name="bucket_name", + storage_id=0, + ) + assert lifecycle is None + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + lifecycle = await async_client.storage.buckets.lifecycle.create( + bucket_name="bucket_name", + storage_id=0, + expiration_days=30, + ) + assert lifecycle is None + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.buckets.lifecycle.with_raw_response.create( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + lifecycle = await response.parse() + assert lifecycle is None + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.storage.buckets.lifecycle.with_streaming_response.create( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + lifecycle = await response.parse() + assert lifecycle is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + await async_client.storage.buckets.lifecycle.with_raw_response.create( + bucket_name="", + storage_id=0, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + lifecycle = await async_client.storage.buckets.lifecycle.delete( + bucket_name="bucket_name", + storage_id=0, + ) + assert lifecycle is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.buckets.lifecycle.with_raw_response.delete( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + lifecycle = await response.parse() + assert lifecycle is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.storage.buckets.lifecycle.with_streaming_response.delete( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + lifecycle = await response.parse() + assert lifecycle is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + await async_client.storage.buckets.lifecycle.with_raw_response.delete( + bucket_name="", + storage_id=0, + ) diff --git a/tests/api_resources/storage/buckets/test_policy.py b/tests/api_resources/storage/buckets/test_policy.py new file mode 100644 index 00000000..fd0a5c06 --- /dev/null +++ b/tests/api_resources/storage/buckets/test_policy.py @@ -0,0 +1,276 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.storage.buckets import PolicyGetResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPolicy: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + policy = client.storage.buckets.policy.create( + bucket_name="bucket_name", + storage_id=0, + ) + assert policy is None + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.storage.buckets.policy.with_raw_response.create( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert policy is None + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.storage.buckets.policy.with_streaming_response.create( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert policy is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + client.storage.buckets.policy.with_raw_response.create( + bucket_name="", + storage_id=0, + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + policy = client.storage.buckets.policy.delete( + bucket_name="bucket_name", + storage_id=0, + ) + assert policy is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.storage.buckets.policy.with_raw_response.delete( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert policy is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.storage.buckets.policy.with_streaming_response.delete( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert policy is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + client.storage.buckets.policy.with_raw_response.delete( + bucket_name="", + storage_id=0, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + policy = client.storage.buckets.policy.get( + bucket_name="bucket_name", + storage_id=0, + ) + assert_matches_type(PolicyGetResponse, policy, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.storage.buckets.policy.with_raw_response.get( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = response.parse() + assert_matches_type(PolicyGetResponse, policy, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.storage.buckets.policy.with_streaming_response.get( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = response.parse() + assert_matches_type(PolicyGetResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + client.storage.buckets.policy.with_raw_response.get( + bucket_name="", + storage_id=0, + ) + + +class TestAsyncPolicy: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + policy = await async_client.storage.buckets.policy.create( + bucket_name="bucket_name", + storage_id=0, + ) + assert policy is None + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.buckets.policy.with_raw_response.create( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert policy is None + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.storage.buckets.policy.with_streaming_response.create( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert policy is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + await async_client.storage.buckets.policy.with_raw_response.create( + bucket_name="", + storage_id=0, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + policy = await async_client.storage.buckets.policy.delete( + bucket_name="bucket_name", + storage_id=0, + ) + assert policy is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.buckets.policy.with_raw_response.delete( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert policy is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.storage.buckets.policy.with_streaming_response.delete( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert policy is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + await async_client.storage.buckets.policy.with_raw_response.delete( + bucket_name="", + storage_id=0, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + policy = await async_client.storage.buckets.policy.get( + bucket_name="bucket_name", + storage_id=0, + ) + assert_matches_type(PolicyGetResponse, policy, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.buckets.policy.with_raw_response.get( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + policy = await response.parse() + assert_matches_type(PolicyGetResponse, policy, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.storage.buckets.policy.with_streaming_response.get( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + policy = await response.parse() + assert_matches_type(PolicyGetResponse, policy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + await async_client.storage.buckets.policy.with_raw_response.get( + bucket_name="", + storage_id=0, + ) diff --git a/tests/api_resources/storage/test_buckets.py b/tests/api_resources/storage/test_buckets.py new file mode 100644 index 00000000..eabe5253 --- /dev/null +++ b/tests/api_resources/storage/test_buckets.py @@ -0,0 +1,273 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.storage import Bucket + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBuckets: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + bucket = client.storage.buckets.create( + bucket_name="bucket_name", + storage_id=0, + ) + assert bucket is None + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.storage.buckets.with_raw_response.create( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bucket = response.parse() + assert bucket is None + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.storage.buckets.with_streaming_response.create( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bucket = response.parse() + assert bucket is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + client.storage.buckets.with_raw_response.create( + bucket_name="", + storage_id=0, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + bucket = client.storage.buckets.list( + storage_id=0, + ) + assert_matches_type(SyncOffsetPage[Bucket], bucket, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + bucket = client.storage.buckets.list( + storage_id=0, + limit=1, + offset=0, + ) + assert_matches_type(SyncOffsetPage[Bucket], bucket, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.storage.buckets.with_raw_response.list( + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bucket = response.parse() + assert_matches_type(SyncOffsetPage[Bucket], bucket, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.storage.buckets.with_streaming_response.list( + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bucket = response.parse() + assert_matches_type(SyncOffsetPage[Bucket], bucket, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + bucket = client.storage.buckets.delete( + bucket_name="bucket_name", + storage_id=0, + ) + assert bucket is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.storage.buckets.with_raw_response.delete( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bucket = response.parse() + assert bucket is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.storage.buckets.with_streaming_response.delete( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bucket = response.parse() + assert bucket is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + client.storage.buckets.with_raw_response.delete( + bucket_name="", + storage_id=0, + ) + + +class TestAsyncBuckets: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + bucket = await async_client.storage.buckets.create( + bucket_name="bucket_name", + storage_id=0, + ) + assert bucket is None + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.buckets.with_raw_response.create( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bucket = await response.parse() + assert bucket is None + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.storage.buckets.with_streaming_response.create( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bucket = await response.parse() + assert bucket is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + await async_client.storage.buckets.with_raw_response.create( + bucket_name="", + storage_id=0, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + bucket = await async_client.storage.buckets.list( + storage_id=0, + ) + assert_matches_type(AsyncOffsetPage[Bucket], bucket, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + bucket = await async_client.storage.buckets.list( + storage_id=0, + limit=1, + offset=0, + ) + assert_matches_type(AsyncOffsetPage[Bucket], bucket, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.buckets.with_raw_response.list( + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bucket = await response.parse() + assert_matches_type(AsyncOffsetPage[Bucket], bucket, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.storage.buckets.with_streaming_response.list( + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bucket = await response.parse() + assert_matches_type(AsyncOffsetPage[Bucket], bucket, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + bucket = await async_client.storage.buckets.delete( + bucket_name="bucket_name", + storage_id=0, + ) + assert bucket is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.buckets.with_raw_response.delete( + bucket_name="bucket_name", + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bucket = await response.parse() + assert bucket is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.storage.buckets.with_streaming_response.delete( + bucket_name="bucket_name", + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bucket = await response.parse() + assert bucket is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"): + await async_client.storage.buckets.with_raw_response.delete( + bucket_name="", + storage_id=0, + ) diff --git a/tests/api_resources/storage/test_credentials.py b/tests/api_resources/storage/test_credentials.py new file mode 100644 index 00000000..8f02e9d0 --- /dev/null +++ b/tests/api_resources/storage/test_credentials.py @@ -0,0 +1,110 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.storage import Storage + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCredentials: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_recreate(self, client: Gcore) -> None: + credential = client.storage.credentials.recreate( + storage_id=0, + ) + assert_matches_type(Storage, credential, path=["response"]) + + @parametrize + def test_method_recreate_with_all_params(self, client: Gcore) -> None: + credential = client.storage.credentials.recreate( + storage_id=0, + delete_sftp_password=True, + generate_s3_keys=True, + generate_sftp_password=True, + reset_sftp_keys=True, + sftp_password="sftp_password", + ) + assert_matches_type(Storage, credential, path=["response"]) + + @parametrize + def test_raw_response_recreate(self, client: Gcore) -> None: + response = client.storage.credentials.with_raw_response.recreate( + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + credential = response.parse() + assert_matches_type(Storage, credential, path=["response"]) + + @parametrize + def test_streaming_response_recreate(self, client: Gcore) -> None: + with client.storage.credentials.with_streaming_response.recreate( + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + credential = response.parse() + assert_matches_type(Storage, credential, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncCredentials: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_recreate(self, async_client: AsyncGcore) -> None: + credential = await async_client.storage.credentials.recreate( + storage_id=0, + ) + assert_matches_type(Storage, credential, path=["response"]) + + @parametrize + async def test_method_recreate_with_all_params(self, async_client: AsyncGcore) -> None: + credential = await async_client.storage.credentials.recreate( + storage_id=0, + delete_sftp_password=True, + generate_s3_keys=True, + generate_sftp_password=True, + reset_sftp_keys=True, + sftp_password="sftp_password", + ) + assert_matches_type(Storage, credential, path=["response"]) + + @parametrize + async def test_raw_response_recreate(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.credentials.with_raw_response.recreate( + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + credential = await response.parse() + assert_matches_type(Storage, credential, path=["response"]) + + @parametrize + async def test_streaming_response_recreate(self, async_client: AsyncGcore) -> None: + async with async_client.storage.credentials.with_streaming_response.recreate( + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + credential = await response.parse() + assert_matches_type(Storage, credential, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/storage/test_locations.py b/tests/api_resources/storage/test_locations.py new file mode 100644 index 00000000..f076ff9b --- /dev/null +++ b/tests/api_resources/storage/test_locations.py @@ -0,0 +1,91 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.storage import Location + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestLocations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + location = client.storage.locations.list() + assert_matches_type(SyncOffsetPage[Location], location, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + location = client.storage.locations.list( + limit=1, + offset=0, + ) + assert_matches_type(SyncOffsetPage[Location], location, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.storage.locations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + location = response.parse() + assert_matches_type(SyncOffsetPage[Location], location, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.storage.locations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + location = response.parse() + assert_matches_type(SyncOffsetPage[Location], location, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncLocations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + location = await async_client.storage.locations.list() + assert_matches_type(AsyncOffsetPage[Location], location, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + location = await async_client.storage.locations.list( + limit=1, + offset=0, + ) + assert_matches_type(AsyncOffsetPage[Location], location, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.locations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + location = await response.parse() + assert_matches_type(AsyncOffsetPage[Location], location, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.storage.locations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + location = await response.parse() + assert_matches_type(AsyncOffsetPage[Location], location, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/storage/test_statistics.py b/tests/api_resources/storage/test_statistics.py new file mode 100644 index 00000000..7bcb3e22 --- /dev/null +++ b/tests/api_resources/storage/test_statistics.py @@ -0,0 +1,173 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.storage import ( + UsageTotal, + StatisticGetUsageSeriesResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestStatistics: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_usage_aggregated(self, client: Gcore) -> None: + statistic = client.storage.statistics.get_usage_aggregated() + assert_matches_type(UsageTotal, statistic, path=["response"]) + + @parametrize + def test_method_get_usage_aggregated_with_all_params(self, client: Gcore) -> None: + statistic = client.storage.statistics.get_usage_aggregated( + from_="2006-01-02", + locations=["s-region-1", "s-region-2"], + storages=["123-myStorage"], + to="2006-01-02", + ) + assert_matches_type(UsageTotal, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_usage_aggregated(self, client: Gcore) -> None: + response = client.storage.statistics.with_raw_response.get_usage_aggregated() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(UsageTotal, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_usage_aggregated(self, client: Gcore) -> None: + with client.storage.statistics.with_streaming_response.get_usage_aggregated() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(UsageTotal, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_usage_series(self, client: Gcore) -> None: + statistic = client.storage.statistics.get_usage_series() + assert_matches_type(StatisticGetUsageSeriesResponse, statistic, path=["response"]) + + @parametrize + def test_method_get_usage_series_with_all_params(self, client: Gcore) -> None: + statistic = client.storage.statistics.get_usage_series( + from_="2006-01-02", + granularity="12h", + locations=["s-region-1", "s-region-2"], + source=0, + storages=["123-myStorage"], + to="2006-01-02", + ts_string=True, + ) + assert_matches_type(StatisticGetUsageSeriesResponse, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_usage_series(self, client: Gcore) -> None: + response = client.storage.statistics.with_raw_response.get_usage_series() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(StatisticGetUsageSeriesResponse, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_usage_series(self, client: Gcore) -> None: + with client.storage.statistics.with_streaming_response.get_usage_series() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(StatisticGetUsageSeriesResponse, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncStatistics: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_usage_aggregated(self, async_client: AsyncGcore) -> None: + statistic = await async_client.storage.statistics.get_usage_aggregated() + assert_matches_type(UsageTotal, statistic, path=["response"]) + + @parametrize + async def test_method_get_usage_aggregated_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.storage.statistics.get_usage_aggregated( + from_="2006-01-02", + locations=["s-region-1", "s-region-2"], + storages=["123-myStorage"], + to="2006-01-02", + ) + assert_matches_type(UsageTotal, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_usage_aggregated(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.statistics.with_raw_response.get_usage_aggregated() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(UsageTotal, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_usage_aggregated(self, async_client: AsyncGcore) -> None: + async with async_client.storage.statistics.with_streaming_response.get_usage_aggregated() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(UsageTotal, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_usage_series(self, async_client: AsyncGcore) -> None: + statistic = await async_client.storage.statistics.get_usage_series() + assert_matches_type(StatisticGetUsageSeriesResponse, statistic, path=["response"]) + + @parametrize + async def test_method_get_usage_series_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.storage.statistics.get_usage_series( + from_="2006-01-02", + granularity="12h", + locations=["s-region-1", "s-region-2"], + source=0, + storages=["123-myStorage"], + to="2006-01-02", + ts_string=True, + ) + assert_matches_type(StatisticGetUsageSeriesResponse, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_usage_series(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.statistics.with_raw_response.get_usage_series() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(StatisticGetUsageSeriesResponse, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_usage_series(self, async_client: AsyncGcore) -> None: + async with async_client.storage.statistics.with_streaming_response.get_usage_series() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(StatisticGetUsageSeriesResponse, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/streaming/__init__.py b/tests/api_resources/streaming/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/streaming/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/streaming/streams/__init__.py b/tests/api_resources/streaming/streams/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/streaming/streams/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/streaming/streams/test_overlays.py b/tests/api_resources/streaming/streams/test_overlays.py new file mode 100644 index 00000000..dbf6f70c --- /dev/null +++ b/tests/api_resources/streaming/streams/test_overlays.py @@ -0,0 +1,517 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.streaming.streams import ( + Overlay, + OverlayListResponse, + OverlayCreateResponse, + OverlayUpdateMultipleResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestOverlays: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + overlay = client.streaming.streams.overlays.create( + stream_id=0, + ) + assert_matches_type(OverlayCreateResponse, overlay, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + overlay = client.streaming.streams.overlays.create( + stream_id=0, + body=[ + { + "url": "http://domain.com/myoverlay1.html", + "height": 40, + "stretch": False, + "width": 120, + "x": 30, + "y": 30, + } + ], + ) + assert_matches_type(OverlayCreateResponse, overlay, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.streaming.streams.overlays.with_raw_response.create( + stream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + overlay = response.parse() + assert_matches_type(OverlayCreateResponse, overlay, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.streaming.streams.overlays.with_streaming_response.create( + stream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + overlay = response.parse() + assert_matches_type(OverlayCreateResponse, overlay, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + overlay = client.streaming.streams.overlays.update( + overlay_id=0, + stream_id=0, + ) + assert_matches_type(Overlay, overlay, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + overlay = client.streaming.streams.overlays.update( + overlay_id=0, + stream_id=0, + height=0, + stretch=True, + url="http://domain.com/myoverlay_new_3.html", + width=0, + x=0, + y=0, + ) + assert_matches_type(Overlay, overlay, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.streaming.streams.overlays.with_raw_response.update( + overlay_id=0, + stream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + overlay = response.parse() + assert_matches_type(Overlay, overlay, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.streaming.streams.overlays.with_streaming_response.update( + overlay_id=0, + stream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + overlay = response.parse() + assert_matches_type(Overlay, overlay, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + overlay = client.streaming.streams.overlays.list( + 0, + ) + assert_matches_type(OverlayListResponse, overlay, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.streaming.streams.overlays.with_raw_response.list( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + overlay = response.parse() + assert_matches_type(OverlayListResponse, overlay, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.streaming.streams.overlays.with_streaming_response.list( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + overlay = response.parse() + assert_matches_type(OverlayListResponse, overlay, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + overlay = client.streaming.streams.overlays.delete( + overlay_id=0, + stream_id=0, + ) + assert overlay is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.streaming.streams.overlays.with_raw_response.delete( + overlay_id=0, + stream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + overlay = response.parse() + assert overlay is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.streaming.streams.overlays.with_streaming_response.delete( + overlay_id=0, + stream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + overlay = response.parse() + assert overlay is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + overlay = client.streaming.streams.overlays.get( + overlay_id=0, + stream_id=0, + ) + assert_matches_type(Overlay, overlay, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.streaming.streams.overlays.with_raw_response.get( + overlay_id=0, + stream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + overlay = response.parse() + assert_matches_type(Overlay, overlay, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.streaming.streams.overlays.with_streaming_response.get( + overlay_id=0, + stream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + overlay = response.parse() + assert_matches_type(Overlay, overlay, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update_multiple(self, client: Gcore) -> None: + overlay = client.streaming.streams.overlays.update_multiple( + stream_id=0, + ) + assert_matches_type(OverlayUpdateMultipleResponse, overlay, path=["response"]) + + @parametrize + def test_method_update_multiple_with_all_params(self, client: Gcore) -> None: + overlay = client.streaming.streams.overlays.update_multiple( + stream_id=0, + body=[ + { + "id": 0, + "height": 0, + "stretch": True, + "url": "url", + "width": 0, + "x": 0, + "y": 0, + } + ], + ) + assert_matches_type(OverlayUpdateMultipleResponse, overlay, path=["response"]) + + @parametrize + def test_raw_response_update_multiple(self, client: Gcore) -> None: + response = client.streaming.streams.overlays.with_raw_response.update_multiple( + stream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + overlay = response.parse() + assert_matches_type(OverlayUpdateMultipleResponse, overlay, path=["response"]) + + @parametrize + def test_streaming_response_update_multiple(self, client: Gcore) -> None: + with client.streaming.streams.overlays.with_streaming_response.update_multiple( + stream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + overlay = response.parse() + assert_matches_type(OverlayUpdateMultipleResponse, overlay, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncOverlays: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + overlay = await async_client.streaming.streams.overlays.create( + stream_id=0, + ) + assert_matches_type(OverlayCreateResponse, overlay, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + overlay = await async_client.streaming.streams.overlays.create( + stream_id=0, + body=[ + { + "url": "http://domain.com/myoverlay1.html", + "height": 40, + "stretch": False, + "width": 120, + "x": 30, + "y": 30, + } + ], + ) + assert_matches_type(OverlayCreateResponse, overlay, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.overlays.with_raw_response.create( + stream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + overlay = await response.parse() + assert_matches_type(OverlayCreateResponse, overlay, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.overlays.with_streaming_response.create( + stream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + overlay = await response.parse() + assert_matches_type(OverlayCreateResponse, overlay, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + overlay = await async_client.streaming.streams.overlays.update( + overlay_id=0, + stream_id=0, + ) + assert_matches_type(Overlay, overlay, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + overlay = await async_client.streaming.streams.overlays.update( + overlay_id=0, + stream_id=0, + height=0, + stretch=True, + url="http://domain.com/myoverlay_new_3.html", + width=0, + x=0, + y=0, + ) + assert_matches_type(Overlay, overlay, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.overlays.with_raw_response.update( + overlay_id=0, + stream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + overlay = await response.parse() + assert_matches_type(Overlay, overlay, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.overlays.with_streaming_response.update( + overlay_id=0, + stream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + overlay = await response.parse() + assert_matches_type(Overlay, overlay, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + overlay = await async_client.streaming.streams.overlays.list( + 0, + ) + assert_matches_type(OverlayListResponse, overlay, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.overlays.with_raw_response.list( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + overlay = await response.parse() + assert_matches_type(OverlayListResponse, overlay, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.overlays.with_streaming_response.list( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + overlay = await response.parse() + assert_matches_type(OverlayListResponse, overlay, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + overlay = await async_client.streaming.streams.overlays.delete( + overlay_id=0, + stream_id=0, + ) + assert overlay is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.overlays.with_raw_response.delete( + overlay_id=0, + stream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + overlay = await response.parse() + assert overlay is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.overlays.with_streaming_response.delete( + overlay_id=0, + stream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + overlay = await response.parse() + assert overlay is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + overlay = await async_client.streaming.streams.overlays.get( + overlay_id=0, + stream_id=0, + ) + assert_matches_type(Overlay, overlay, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.overlays.with_raw_response.get( + overlay_id=0, + stream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + overlay = await response.parse() + assert_matches_type(Overlay, overlay, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.overlays.with_streaming_response.get( + overlay_id=0, + stream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + overlay = await response.parse() + assert_matches_type(Overlay, overlay, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update_multiple(self, async_client: AsyncGcore) -> None: + overlay = await async_client.streaming.streams.overlays.update_multiple( + stream_id=0, + ) + assert_matches_type(OverlayUpdateMultipleResponse, overlay, path=["response"]) + + @parametrize + async def test_method_update_multiple_with_all_params(self, async_client: AsyncGcore) -> None: + overlay = await async_client.streaming.streams.overlays.update_multiple( + stream_id=0, + body=[ + { + "id": 0, + "height": 0, + "stretch": True, + "url": "url", + "width": 0, + "x": 0, + "y": 0, + } + ], + ) + assert_matches_type(OverlayUpdateMultipleResponse, overlay, path=["response"]) + + @parametrize + async def test_raw_response_update_multiple(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.overlays.with_raw_response.update_multiple( + stream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + overlay = await response.parse() + assert_matches_type(OverlayUpdateMultipleResponse, overlay, path=["response"]) + + @parametrize + async def test_streaming_response_update_multiple(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.overlays.with_streaming_response.update_multiple( + stream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + overlay = await response.parse() + assert_matches_type(OverlayUpdateMultipleResponse, overlay, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/streaming/test_ai_tasks.py b/tests/api_resources/streaming/test_ai_tasks.py new file mode 100644 index 00000000..1e5e36d1 --- /dev/null +++ b/tests/api_resources/streaming/test_ai_tasks.py @@ -0,0 +1,435 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncPageStreamingAI, AsyncPageStreamingAI +from gcore.types.streaming import ( + AITask, + AITaskGetResponse, + AITaskCancelResponse, + AITaskCreateResponse, + AITaskGetAISettingsResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAITasks: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + ai_task = client.streaming.ai_tasks.create( + task_name="transcription", + url="url", + ) + assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + ai_task = client.streaming.ai_tasks.create( + task_name="transcription", + url="url", + audio_language="audio_language", + category="sport", + client_entity_data="client_entity_data", + client_user_id="client_user_id", + subtitles_language="subtitles_language", + ) + assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.streaming.ai_tasks.with_raw_response.create( + task_name="transcription", + url="url", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ai_task = response.parse() + assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.streaming.ai_tasks.with_streaming_response.create( + task_name="transcription", + url="url", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ai_task = response.parse() + assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + ai_task = client.streaming.ai_tasks.list() + assert_matches_type(SyncPageStreamingAI[AITask], ai_task, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + ai_task = client.streaming.ai_tasks.list( + date_created="date_created", + limit=0, + ordering="task_id", + page=0, + search="search", + status="FAILURE", + task_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + task_name="transcription", + ) + assert_matches_type(SyncPageStreamingAI[AITask], ai_task, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.streaming.ai_tasks.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ai_task = response.parse() + assert_matches_type(SyncPageStreamingAI[AITask], ai_task, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.streaming.ai_tasks.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ai_task = response.parse() + assert_matches_type(SyncPageStreamingAI[AITask], ai_task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_cancel(self, client: Gcore) -> None: + ai_task = client.streaming.ai_tasks.cancel( + "task_id", + ) + assert_matches_type(AITaskCancelResponse, ai_task, path=["response"]) + + @parametrize + def test_raw_response_cancel(self, client: Gcore) -> None: + response = client.streaming.ai_tasks.with_raw_response.cancel( + "task_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ai_task = response.parse() + assert_matches_type(AITaskCancelResponse, ai_task, path=["response"]) + + @parametrize + def test_streaming_response_cancel(self, client: Gcore) -> None: + with client.streaming.ai_tasks.with_streaming_response.cancel( + "task_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ai_task = response.parse() + assert_matches_type(AITaskCancelResponse, ai_task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_cancel(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `task_id` but received ''"): + client.streaming.ai_tasks.with_raw_response.cancel( + "", + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + ai_task = client.streaming.ai_tasks.get( + "task_id", + ) + assert_matches_type(AITaskGetResponse, ai_task, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.streaming.ai_tasks.with_raw_response.get( + "task_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ai_task = response.parse() + assert_matches_type(AITaskGetResponse, ai_task, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.streaming.ai_tasks.with_streaming_response.get( + "task_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ai_task = response.parse() + assert_matches_type(AITaskGetResponse, ai_task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `task_id` but received ''"): + client.streaming.ai_tasks.with_raw_response.get( + "", + ) + + @parametrize + def test_method_get_ai_settings(self, client: Gcore) -> None: + ai_task = client.streaming.ai_tasks.get_ai_settings( + type="language_support", + ) + assert_matches_type(AITaskGetAISettingsResponse, ai_task, path=["response"]) + + @parametrize + def test_method_get_ai_settings_with_all_params(self, client: Gcore) -> None: + ai_task = client.streaming.ai_tasks.get_ai_settings( + type="language_support", + audio_language="audio_language", + subtitles_language="subtitles_language", + ) + assert_matches_type(AITaskGetAISettingsResponse, ai_task, path=["response"]) + + @parametrize + def test_raw_response_get_ai_settings(self, client: Gcore) -> None: + response = client.streaming.ai_tasks.with_raw_response.get_ai_settings( + type="language_support", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ai_task = response.parse() + assert_matches_type(AITaskGetAISettingsResponse, ai_task, path=["response"]) + + @parametrize + def test_streaming_response_get_ai_settings(self, client: Gcore) -> None: + with client.streaming.ai_tasks.with_streaming_response.get_ai_settings( + type="language_support", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ai_task = response.parse() + assert_matches_type(AITaskGetAISettingsResponse, ai_task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAITasks: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + ai_task = await async_client.streaming.ai_tasks.create( + task_name="transcription", + url="url", + ) + assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + ai_task = await async_client.streaming.ai_tasks.create( + task_name="transcription", + url="url", + audio_language="audio_language", + category="sport", + client_entity_data="client_entity_data", + client_user_id="client_user_id", + subtitles_language="subtitles_language", + ) + assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.ai_tasks.with_raw_response.create( + task_name="transcription", + url="url", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ai_task = await response.parse() + assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.ai_tasks.with_streaming_response.create( + task_name="transcription", + url="url", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ai_task = await response.parse() + assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + ai_task = await async_client.streaming.ai_tasks.list() + assert_matches_type(AsyncPageStreamingAI[AITask], ai_task, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + ai_task = await async_client.streaming.ai_tasks.list( + date_created="date_created", + limit=0, + ordering="task_id", + page=0, + search="search", + status="FAILURE", + task_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + task_name="transcription", + ) + assert_matches_type(AsyncPageStreamingAI[AITask], ai_task, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.ai_tasks.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ai_task = await response.parse() + assert_matches_type(AsyncPageStreamingAI[AITask], ai_task, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.ai_tasks.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ai_task = await response.parse() + assert_matches_type(AsyncPageStreamingAI[AITask], ai_task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_cancel(self, async_client: AsyncGcore) -> None: + ai_task = await async_client.streaming.ai_tasks.cancel( + "task_id", + ) + assert_matches_type(AITaskCancelResponse, ai_task, path=["response"]) + + @parametrize + async def test_raw_response_cancel(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.ai_tasks.with_raw_response.cancel( + "task_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ai_task = await response.parse() + assert_matches_type(AITaskCancelResponse, ai_task, path=["response"]) + + @parametrize + async def test_streaming_response_cancel(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.ai_tasks.with_streaming_response.cancel( + "task_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ai_task = await response.parse() + assert_matches_type(AITaskCancelResponse, ai_task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_cancel(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `task_id` but received ''"): + await async_client.streaming.ai_tasks.with_raw_response.cancel( + "", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + ai_task = await async_client.streaming.ai_tasks.get( + "task_id", + ) + assert_matches_type(AITaskGetResponse, ai_task, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.ai_tasks.with_raw_response.get( + "task_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ai_task = await response.parse() + assert_matches_type(AITaskGetResponse, ai_task, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.ai_tasks.with_streaming_response.get( + "task_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ai_task = await response.parse() + assert_matches_type(AITaskGetResponse, ai_task, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `task_id` but received ''"): + await async_client.streaming.ai_tasks.with_raw_response.get( + "", + ) + + @parametrize + async def test_method_get_ai_settings(self, async_client: AsyncGcore) -> None: + ai_task = await async_client.streaming.ai_tasks.get_ai_settings( + type="language_support", + ) + assert_matches_type(AITaskGetAISettingsResponse, ai_task, path=["response"]) + + @parametrize + async def test_method_get_ai_settings_with_all_params(self, async_client: AsyncGcore) -> None: + ai_task = await async_client.streaming.ai_tasks.get_ai_settings( + type="language_support", + audio_language="audio_language", + subtitles_language="subtitles_language", + ) + assert_matches_type(AITaskGetAISettingsResponse, ai_task, path=["response"]) + + @parametrize + async def test_raw_response_get_ai_settings(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.ai_tasks.with_raw_response.get_ai_settings( + type="language_support", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ai_task = await response.parse() + assert_matches_type(AITaskGetAISettingsResponse, ai_task, path=["response"]) + + @parametrize + async def test_streaming_response_get_ai_settings(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.ai_tasks.with_streaming_response.get_ai_settings( + type="language_support", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ai_task = await response.parse() + assert_matches_type(AITaskGetAISettingsResponse, ai_task, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/streaming/test_broadcasts.py b/tests/api_resources/streaming/test_broadcasts.py new file mode 100644 index 00000000..79118259 --- /dev/null +++ b/tests/api_resources/streaming/test_broadcasts.py @@ -0,0 +1,464 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncPageStreaming, AsyncPageStreaming +from gcore.types.streaming import ( + Broadcast, + BroadcastSpectatorsCount, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBroadcasts: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + broadcast = client.streaming.broadcasts.create() + assert broadcast is None + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + broadcast = client.streaming.broadcasts.create( + broadcast={ + "name": "Broadcast", + "ad_id": 1, + "custom_iframe_url": "", + "pending_message": "pending_message", + "player_id": 14, + "poster": "poster", + "share_url": "", + "show_dvr_after_finish": True, + "status": "live", + "stream_ids": [10], + }, + ) + assert broadcast is None + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.streaming.broadcasts.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = response.parse() + assert broadcast is None + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.streaming.broadcasts.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = response.parse() + assert broadcast is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + broadcast = client.streaming.broadcasts.update( + broadcast_id=0, + ) + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + broadcast = client.streaming.broadcasts.update( + broadcast_id=0, + broadcast={ + "name": "Broadcast", + "ad_id": 1, + "custom_iframe_url": "", + "pending_message": "pending_message", + "player_id": 14, + "poster": "poster", + "share_url": "", + "show_dvr_after_finish": True, + "status": "live", + "stream_ids": [10], + }, + ) + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.streaming.broadcasts.with_raw_response.update( + broadcast_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = response.parse() + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.streaming.broadcasts.with_streaming_response.update( + broadcast_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = response.parse() + assert_matches_type(Broadcast, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + broadcast = client.streaming.broadcasts.list() + assert_matches_type(SyncPageStreaming[Broadcast], broadcast, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + broadcast = client.streaming.broadcasts.list( + page=0, + ) + assert_matches_type(SyncPageStreaming[Broadcast], broadcast, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.streaming.broadcasts.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = response.parse() + assert_matches_type(SyncPageStreaming[Broadcast], broadcast, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.streaming.broadcasts.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = response.parse() + assert_matches_type(SyncPageStreaming[Broadcast], broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + broadcast = client.streaming.broadcasts.delete( + 0, + ) + assert broadcast is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.streaming.broadcasts.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = response.parse() + assert broadcast is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.streaming.broadcasts.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = response.parse() + assert broadcast is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + broadcast = client.streaming.broadcasts.get( + 0, + ) + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.streaming.broadcasts.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = response.parse() + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.streaming.broadcasts.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = response.parse() + assert_matches_type(Broadcast, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_spectators_count(self, client: Gcore) -> None: + broadcast = client.streaming.broadcasts.get_spectators_count( + 0, + ) + assert_matches_type(BroadcastSpectatorsCount, broadcast, path=["response"]) + + @parametrize + def test_raw_response_get_spectators_count(self, client: Gcore) -> None: + response = client.streaming.broadcasts.with_raw_response.get_spectators_count( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = response.parse() + assert_matches_type(BroadcastSpectatorsCount, broadcast, path=["response"]) + + @parametrize + def test_streaming_response_get_spectators_count(self, client: Gcore) -> None: + with client.streaming.broadcasts.with_streaming_response.get_spectators_count( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = response.parse() + assert_matches_type(BroadcastSpectatorsCount, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncBroadcasts: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + broadcast = await async_client.streaming.broadcasts.create() + assert broadcast is None + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + broadcast = await async_client.streaming.broadcasts.create( + broadcast={ + "name": "Broadcast", + "ad_id": 1, + "custom_iframe_url": "", + "pending_message": "pending_message", + "player_id": 14, + "poster": "poster", + "share_url": "", + "show_dvr_after_finish": True, + "status": "live", + "stream_ids": [10], + }, + ) + assert broadcast is None + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.broadcasts.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = await response.parse() + assert broadcast is None + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.broadcasts.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = await response.parse() + assert broadcast is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + broadcast = await async_client.streaming.broadcasts.update( + broadcast_id=0, + ) + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + broadcast = await async_client.streaming.broadcasts.update( + broadcast_id=0, + broadcast={ + "name": "Broadcast", + "ad_id": 1, + "custom_iframe_url": "", + "pending_message": "pending_message", + "player_id": 14, + "poster": "poster", + "share_url": "", + "show_dvr_after_finish": True, + "status": "live", + "stream_ids": [10], + }, + ) + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.broadcasts.with_raw_response.update( + broadcast_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = await response.parse() + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.broadcasts.with_streaming_response.update( + broadcast_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = await response.parse() + assert_matches_type(Broadcast, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + broadcast = await async_client.streaming.broadcasts.list() + assert_matches_type(AsyncPageStreaming[Broadcast], broadcast, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + broadcast = await async_client.streaming.broadcasts.list( + page=0, + ) + assert_matches_type(AsyncPageStreaming[Broadcast], broadcast, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.broadcasts.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = await response.parse() + assert_matches_type(AsyncPageStreaming[Broadcast], broadcast, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.broadcasts.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = await response.parse() + assert_matches_type(AsyncPageStreaming[Broadcast], broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + broadcast = await async_client.streaming.broadcasts.delete( + 0, + ) + assert broadcast is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.broadcasts.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = await response.parse() + assert broadcast is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.broadcasts.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = await response.parse() + assert broadcast is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + broadcast = await async_client.streaming.broadcasts.get( + 0, + ) + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.broadcasts.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = await response.parse() + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.broadcasts.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = await response.parse() + assert_matches_type(Broadcast, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_spectators_count(self, async_client: AsyncGcore) -> None: + broadcast = await async_client.streaming.broadcasts.get_spectators_count( + 0, + ) + assert_matches_type(BroadcastSpectatorsCount, broadcast, path=["response"]) + + @parametrize + async def test_raw_response_get_spectators_count(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.broadcasts.with_raw_response.get_spectators_count( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = await response.parse() + assert_matches_type(BroadcastSpectatorsCount, broadcast, path=["response"]) + + @parametrize + async def test_streaming_response_get_spectators_count(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.broadcasts.with_streaming_response.get_spectators_count( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = await response.parse() + assert_matches_type(BroadcastSpectatorsCount, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/streaming/test_directories.py b/tests/api_resources/streaming/test_directories.py new file mode 100644 index 00000000..099d8bd6 --- /dev/null +++ b/tests/api_resources/streaming/test_directories.py @@ -0,0 +1,360 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.streaming import ( + DirectoryBase, + DirectoriesTree, + DirectoryGetResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDirectories: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + directory = client.streaming.directories.create( + name="New series. Season 1", + ) + assert_matches_type(DirectoryBase, directory, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + directory = client.streaming.directories.create( + name="New series. Season 1", + parent_id=100, + ) + assert_matches_type(DirectoryBase, directory, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.streaming.directories.with_raw_response.create( + name="New series. Season 1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + directory = response.parse() + assert_matches_type(DirectoryBase, directory, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.streaming.directories.with_streaming_response.create( + name="New series. Season 1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = response.parse() + assert_matches_type(DirectoryBase, directory, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + directory = client.streaming.directories.update( + directory_id=0, + ) + assert_matches_type(DirectoryBase, directory, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + directory = client.streaming.directories.update( + directory_id=0, + name="New series. Season 2", + parent_id=0, + ) + assert_matches_type(DirectoryBase, directory, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.streaming.directories.with_raw_response.update( + directory_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + directory = response.parse() + assert_matches_type(DirectoryBase, directory, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.streaming.directories.with_streaming_response.update( + directory_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = response.parse() + assert_matches_type(DirectoryBase, directory, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + directory = client.streaming.directories.delete( + 0, + ) + assert directory is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.streaming.directories.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + directory = response.parse() + assert directory is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.streaming.directories.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = response.parse() + assert directory is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + directory = client.streaming.directories.get( + 0, + ) + assert_matches_type(DirectoryGetResponse, directory, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.streaming.directories.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + directory = response.parse() + assert_matches_type(DirectoryGetResponse, directory, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.streaming.directories.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = response.parse() + assert_matches_type(DirectoryGetResponse, directory, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_tree(self, client: Gcore) -> None: + directory = client.streaming.directories.get_tree() + assert_matches_type(DirectoriesTree, directory, path=["response"]) + + @parametrize + def test_raw_response_get_tree(self, client: Gcore) -> None: + response = client.streaming.directories.with_raw_response.get_tree() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + directory = response.parse() + assert_matches_type(DirectoriesTree, directory, path=["response"]) + + @parametrize + def test_streaming_response_get_tree(self, client: Gcore) -> None: + with client.streaming.directories.with_streaming_response.get_tree() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = response.parse() + assert_matches_type(DirectoriesTree, directory, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncDirectories: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + directory = await async_client.streaming.directories.create( + name="New series. Season 1", + ) + assert_matches_type(DirectoryBase, directory, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + directory = await async_client.streaming.directories.create( + name="New series. Season 1", + parent_id=100, + ) + assert_matches_type(DirectoryBase, directory, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.directories.with_raw_response.create( + name="New series. Season 1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + directory = await response.parse() + assert_matches_type(DirectoryBase, directory, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.directories.with_streaming_response.create( + name="New series. Season 1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = await response.parse() + assert_matches_type(DirectoryBase, directory, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + directory = await async_client.streaming.directories.update( + directory_id=0, + ) + assert_matches_type(DirectoryBase, directory, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + directory = await async_client.streaming.directories.update( + directory_id=0, + name="New series. Season 2", + parent_id=0, + ) + assert_matches_type(DirectoryBase, directory, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.directories.with_raw_response.update( + directory_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + directory = await response.parse() + assert_matches_type(DirectoryBase, directory, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.directories.with_streaming_response.update( + directory_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = await response.parse() + assert_matches_type(DirectoryBase, directory, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + directory = await async_client.streaming.directories.delete( + 0, + ) + assert directory is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.directories.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + directory = await response.parse() + assert directory is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.directories.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = await response.parse() + assert directory is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + directory = await async_client.streaming.directories.get( + 0, + ) + assert_matches_type(DirectoryGetResponse, directory, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.directories.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + directory = await response.parse() + assert_matches_type(DirectoryGetResponse, directory, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.directories.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = await response.parse() + assert_matches_type(DirectoryGetResponse, directory, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_tree(self, async_client: AsyncGcore) -> None: + directory = await async_client.streaming.directories.get_tree() + assert_matches_type(DirectoriesTree, directory, path=["response"]) + + @parametrize + async def test_raw_response_get_tree(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.directories.with_raw_response.get_tree() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + directory = await response.parse() + assert_matches_type(DirectoriesTree, directory, path=["response"]) + + @parametrize + async def test_streaming_response_get_tree(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.directories.with_streaming_response.get_tree() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + directory = await response.parse() + assert_matches_type(DirectoriesTree, directory, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/streaming/test_players.py b/tests/api_resources/streaming/test_players.py new file mode 100644 index 00000000..1e7bcba9 --- /dev/null +++ b/tests/api_resources/streaming/test_players.py @@ -0,0 +1,501 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncPageStreaming, AsyncPageStreaming +from gcore.types.streaming import Player + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPlayers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + player = client.streaming.players.create() + assert player is None + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + player = client.streaming.players.create( + player={ + "name": "name", + "id": 0, + "autoplay": True, + "bg_color": "bg_color", + "client_id": 0, + "custom_css": "custom_css", + "design": "design", + "disable_skin": True, + "fg_color": "fg_color", + "framework": "framework", + "hover_color": "hover_color", + "js_url": "js_url", + "logo": "logo", + "logo_position": "logo_position", + "mute": True, + "save_options_to_cookies": True, + "show_sharing": True, + "skin_is_url": "skin_is_url", + "speed_control": True, + "text_color": "text_color", + }, + ) + assert player is None + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.streaming.players.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + player = response.parse() + assert player is None + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.streaming.players.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + player = response.parse() + assert player is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + player = client.streaming.players.update( + player_id=0, + ) + assert_matches_type(Player, player, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + player = client.streaming.players.update( + player_id=0, + player={ + "name": "name", + "id": 0, + "autoplay": True, + "bg_color": "bg_color", + "client_id": 0, + "custom_css": "custom_css", + "design": "design", + "disable_skin": True, + "fg_color": "fg_color", + "framework": "framework", + "hover_color": "hover_color", + "js_url": "js_url", + "logo": "logo", + "logo_position": "logo_position", + "mute": True, + "save_options_to_cookies": True, + "show_sharing": True, + "skin_is_url": "skin_is_url", + "speed_control": True, + "text_color": "text_color", + }, + ) + assert_matches_type(Player, player, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.streaming.players.with_raw_response.update( + player_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + player = response.parse() + assert_matches_type(Player, player, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.streaming.players.with_streaming_response.update( + player_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + player = response.parse() + assert_matches_type(Player, player, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + player = client.streaming.players.list() + assert_matches_type(SyncPageStreaming[Player], player, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + player = client.streaming.players.list( + page=0, + ) + assert_matches_type(SyncPageStreaming[Player], player, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.streaming.players.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + player = response.parse() + assert_matches_type(SyncPageStreaming[Player], player, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.streaming.players.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + player = response.parse() + assert_matches_type(SyncPageStreaming[Player], player, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + player = client.streaming.players.delete( + 0, + ) + assert player is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.streaming.players.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + player = response.parse() + assert player is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.streaming.players.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + player = response.parse() + assert player is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + player = client.streaming.players.get( + 0, + ) + assert_matches_type(Player, player, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.streaming.players.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + player = response.parse() + assert_matches_type(Player, player, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.streaming.players.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + player = response.parse() + assert_matches_type(Player, player, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_preview(self, client: Gcore) -> None: + player = client.streaming.players.preview( + 0, + ) + assert player is None + + @parametrize + def test_raw_response_preview(self, client: Gcore) -> None: + response = client.streaming.players.with_raw_response.preview( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + player = response.parse() + assert player is None + + @parametrize + def test_streaming_response_preview(self, client: Gcore) -> None: + with client.streaming.players.with_streaming_response.preview( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + player = response.parse() + assert player is None + + assert cast(Any, response.is_closed) is True + + +class TestAsyncPlayers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + player = await async_client.streaming.players.create() + assert player is None + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + player = await async_client.streaming.players.create( + player={ + "name": "name", + "id": 0, + "autoplay": True, + "bg_color": "bg_color", + "client_id": 0, + "custom_css": "custom_css", + "design": "design", + "disable_skin": True, + "fg_color": "fg_color", + "framework": "framework", + "hover_color": "hover_color", + "js_url": "js_url", + "logo": "logo", + "logo_position": "logo_position", + "mute": True, + "save_options_to_cookies": True, + "show_sharing": True, + "skin_is_url": "skin_is_url", + "speed_control": True, + "text_color": "text_color", + }, + ) + assert player is None + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.players.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + player = await response.parse() + assert player is None + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.players.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + player = await response.parse() + assert player is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + player = await async_client.streaming.players.update( + player_id=0, + ) + assert_matches_type(Player, player, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + player = await async_client.streaming.players.update( + player_id=0, + player={ + "name": "name", + "id": 0, + "autoplay": True, + "bg_color": "bg_color", + "client_id": 0, + "custom_css": "custom_css", + "design": "design", + "disable_skin": True, + "fg_color": "fg_color", + "framework": "framework", + "hover_color": "hover_color", + "js_url": "js_url", + "logo": "logo", + "logo_position": "logo_position", + "mute": True, + "save_options_to_cookies": True, + "show_sharing": True, + "skin_is_url": "skin_is_url", + "speed_control": True, + "text_color": "text_color", + }, + ) + assert_matches_type(Player, player, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.players.with_raw_response.update( + player_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + player = await response.parse() + assert_matches_type(Player, player, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.players.with_streaming_response.update( + player_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + player = await response.parse() + assert_matches_type(Player, player, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + player = await async_client.streaming.players.list() + assert_matches_type(AsyncPageStreaming[Player], player, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + player = await async_client.streaming.players.list( + page=0, + ) + assert_matches_type(AsyncPageStreaming[Player], player, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.players.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + player = await response.parse() + assert_matches_type(AsyncPageStreaming[Player], player, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.players.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + player = await response.parse() + assert_matches_type(AsyncPageStreaming[Player], player, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + player = await async_client.streaming.players.delete( + 0, + ) + assert player is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.players.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + player = await response.parse() + assert player is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.players.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + player = await response.parse() + assert player is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + player = await async_client.streaming.players.get( + 0, + ) + assert_matches_type(Player, player, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.players.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + player = await response.parse() + assert_matches_type(Player, player, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.players.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + player = await response.parse() + assert_matches_type(Player, player, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_preview(self, async_client: AsyncGcore) -> None: + player = await async_client.streaming.players.preview( + 0, + ) + assert player is None + + @parametrize + async def test_raw_response_preview(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.players.with_raw_response.preview( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + player = await response.parse() + assert player is None + + @parametrize + async def test_streaming_response_preview(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.players.with_streaming_response.preview( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + player = await response.parse() + assert player is None + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/streaming/test_playlists.py b/tests/api_resources/streaming/test_playlists.py new file mode 100644 index 00000000..753dd073 --- /dev/null +++ b/tests/api_resources/streaming/test_playlists.py @@ -0,0 +1,473 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncPageStreaming, AsyncPageStreaming +from gcore.types.streaming import ( + Playlist, + PlaylistCreated, + PlaylistListVideosResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPlaylists: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + playlist = client.streaming.playlists.create() + assert_matches_type(PlaylistCreated, playlist, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + playlist = client.streaming.playlists.create( + active=True, + ad_id=0, + client_id=0, + client_user_id=2876, + countdown=True, + hls_cmaf_url="hls_cmaf_url", + hls_url="hls_url", + iframe_url="iframe_url", + loop=False, + name="Playlist: Webinar 'Onboarding for new employees on working with the corporate portal'", + player_id=0, + playlist_type="live", + start_time="2024-07-01T11:00:00Z", + video_ids=[17800, 17801], + ) + assert_matches_type(PlaylistCreated, playlist, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.streaming.playlists.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + playlist = response.parse() + assert_matches_type(PlaylistCreated, playlist, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.streaming.playlists.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + playlist = response.parse() + assert_matches_type(PlaylistCreated, playlist, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + playlist = client.streaming.playlists.update( + playlist_id=0, + ) + assert_matches_type(Playlist, playlist, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + playlist = client.streaming.playlists.update( + playlist_id=0, + active=True, + ad_id=0, + client_id=0, + client_user_id=2876, + countdown=True, + hls_cmaf_url="hls_cmaf_url", + hls_url="hls_url", + iframe_url="iframe_url", + loop=False, + name="Playlist: Webinar 'Onboarding for new employees on working with the corporate portal'", + player_id=0, + playlist_type="live", + start_time="2024-07-01T11:00:00Z", + video_ids=[17800, 17801], + ) + assert_matches_type(Playlist, playlist, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.streaming.playlists.with_raw_response.update( + playlist_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + playlist = response.parse() + assert_matches_type(Playlist, playlist, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.streaming.playlists.with_streaming_response.update( + playlist_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + playlist = response.parse() + assert_matches_type(Playlist, playlist, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + playlist = client.streaming.playlists.list() + assert_matches_type(SyncPageStreaming[Playlist], playlist, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + playlist = client.streaming.playlists.list( + page=0, + ) + assert_matches_type(SyncPageStreaming[Playlist], playlist, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.streaming.playlists.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + playlist = response.parse() + assert_matches_type(SyncPageStreaming[Playlist], playlist, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.streaming.playlists.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + playlist = response.parse() + assert_matches_type(SyncPageStreaming[Playlist], playlist, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + playlist = client.streaming.playlists.delete( + 0, + ) + assert playlist is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.streaming.playlists.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + playlist = response.parse() + assert playlist is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.streaming.playlists.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + playlist = response.parse() + assert playlist is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + playlist = client.streaming.playlists.get( + 0, + ) + assert_matches_type(Playlist, playlist, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.streaming.playlists.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + playlist = response.parse() + assert_matches_type(Playlist, playlist, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.streaming.playlists.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + playlist = response.parse() + assert_matches_type(Playlist, playlist, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_videos(self, client: Gcore) -> None: + playlist = client.streaming.playlists.list_videos( + 0, + ) + assert_matches_type(PlaylistListVideosResponse, playlist, path=["response"]) + + @parametrize + def test_raw_response_list_videos(self, client: Gcore) -> None: + response = client.streaming.playlists.with_raw_response.list_videos( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + playlist = response.parse() + assert_matches_type(PlaylistListVideosResponse, playlist, path=["response"]) + + @parametrize + def test_streaming_response_list_videos(self, client: Gcore) -> None: + with client.streaming.playlists.with_streaming_response.list_videos( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + playlist = response.parse() + assert_matches_type(PlaylistListVideosResponse, playlist, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncPlaylists: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + playlist = await async_client.streaming.playlists.create() + assert_matches_type(PlaylistCreated, playlist, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + playlist = await async_client.streaming.playlists.create( + active=True, + ad_id=0, + client_id=0, + client_user_id=2876, + countdown=True, + hls_cmaf_url="hls_cmaf_url", + hls_url="hls_url", + iframe_url="iframe_url", + loop=False, + name="Playlist: Webinar 'Onboarding for new employees on working with the corporate portal'", + player_id=0, + playlist_type="live", + start_time="2024-07-01T11:00:00Z", + video_ids=[17800, 17801], + ) + assert_matches_type(PlaylistCreated, playlist, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.playlists.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + playlist = await response.parse() + assert_matches_type(PlaylistCreated, playlist, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.playlists.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + playlist = await response.parse() + assert_matches_type(PlaylistCreated, playlist, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + playlist = await async_client.streaming.playlists.update( + playlist_id=0, + ) + assert_matches_type(Playlist, playlist, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + playlist = await async_client.streaming.playlists.update( + playlist_id=0, + active=True, + ad_id=0, + client_id=0, + client_user_id=2876, + countdown=True, + hls_cmaf_url="hls_cmaf_url", + hls_url="hls_url", + iframe_url="iframe_url", + loop=False, + name="Playlist: Webinar 'Onboarding for new employees on working with the corporate portal'", + player_id=0, + playlist_type="live", + start_time="2024-07-01T11:00:00Z", + video_ids=[17800, 17801], + ) + assert_matches_type(Playlist, playlist, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.playlists.with_raw_response.update( + playlist_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + playlist = await response.parse() + assert_matches_type(Playlist, playlist, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.playlists.with_streaming_response.update( + playlist_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + playlist = await response.parse() + assert_matches_type(Playlist, playlist, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + playlist = await async_client.streaming.playlists.list() + assert_matches_type(AsyncPageStreaming[Playlist], playlist, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + playlist = await async_client.streaming.playlists.list( + page=0, + ) + assert_matches_type(AsyncPageStreaming[Playlist], playlist, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.playlists.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + playlist = await response.parse() + assert_matches_type(AsyncPageStreaming[Playlist], playlist, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.playlists.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + playlist = await response.parse() + assert_matches_type(AsyncPageStreaming[Playlist], playlist, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + playlist = await async_client.streaming.playlists.delete( + 0, + ) + assert playlist is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.playlists.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + playlist = await response.parse() + assert playlist is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.playlists.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + playlist = await response.parse() + assert playlist is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + playlist = await async_client.streaming.playlists.get( + 0, + ) + assert_matches_type(Playlist, playlist, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.playlists.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + playlist = await response.parse() + assert_matches_type(Playlist, playlist, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.playlists.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + playlist = await response.parse() + assert_matches_type(Playlist, playlist, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_videos(self, async_client: AsyncGcore) -> None: + playlist = await async_client.streaming.playlists.list_videos( + 0, + ) + assert_matches_type(PlaylistListVideosResponse, playlist, path=["response"]) + + @parametrize + async def test_raw_response_list_videos(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.playlists.with_raw_response.list_videos( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + playlist = await response.parse() + assert_matches_type(PlaylistListVideosResponse, playlist, path=["response"]) + + @parametrize + async def test_streaming_response_list_videos(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.playlists.with_streaming_response.list_videos( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + playlist = await response.parse() + assert_matches_type(PlaylistListVideosResponse, playlist, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/streaming/test_quality_sets.py b/tests/api_resources/streaming/test_quality_sets.py new file mode 100644 index 00000000..f98d8092 --- /dev/null +++ b/tests/api_resources/streaming/test_quality_sets.py @@ -0,0 +1,140 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.streaming import QualitySets + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestQualitySets: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + quality_set = client.streaming.quality_sets.list() + assert_matches_type(QualitySets, quality_set, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.streaming.quality_sets.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + quality_set = response.parse() + assert_matches_type(QualitySets, quality_set, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.streaming.quality_sets.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + quality_set = response.parse() + assert_matches_type(QualitySets, quality_set, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_set_default(self, client: Gcore) -> None: + quality_set = client.streaming.quality_sets.set_default() + assert_matches_type(QualitySets, quality_set, path=["response"]) + + @parametrize + def test_method_set_default_with_all_params(self, client: Gcore) -> None: + quality_set = client.streaming.quality_sets.set_default( + live={"id": 0}, + vod={"id": 0}, + ) + assert_matches_type(QualitySets, quality_set, path=["response"]) + + @parametrize + def test_raw_response_set_default(self, client: Gcore) -> None: + response = client.streaming.quality_sets.with_raw_response.set_default() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + quality_set = response.parse() + assert_matches_type(QualitySets, quality_set, path=["response"]) + + @parametrize + def test_streaming_response_set_default(self, client: Gcore) -> None: + with client.streaming.quality_sets.with_streaming_response.set_default() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + quality_set = response.parse() + assert_matches_type(QualitySets, quality_set, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncQualitySets: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + quality_set = await async_client.streaming.quality_sets.list() + assert_matches_type(QualitySets, quality_set, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.quality_sets.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + quality_set = await response.parse() + assert_matches_type(QualitySets, quality_set, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.quality_sets.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + quality_set = await response.parse() + assert_matches_type(QualitySets, quality_set, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_set_default(self, async_client: AsyncGcore) -> None: + quality_set = await async_client.streaming.quality_sets.set_default() + assert_matches_type(QualitySets, quality_set, path=["response"]) + + @parametrize + async def test_method_set_default_with_all_params(self, async_client: AsyncGcore) -> None: + quality_set = await async_client.streaming.quality_sets.set_default( + live={"id": 0}, + vod={"id": 0}, + ) + assert_matches_type(QualitySets, quality_set, path=["response"]) + + @parametrize + async def test_raw_response_set_default(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.quality_sets.with_raw_response.set_default() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + quality_set = await response.parse() + assert_matches_type(QualitySets, quality_set, path=["response"]) + + @parametrize + async def test_streaming_response_set_default(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.quality_sets.with_streaming_response.set_default() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + quality_set = await response.parse() + assert_matches_type(QualitySets, quality_set, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/streaming/test_restreams.py b/tests/api_resources/streaming/test_restreams.py new file mode 100644 index 00000000..0547cf0c --- /dev/null +++ b/tests/api_resources/streaming/test_restreams.py @@ -0,0 +1,383 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncPageStreaming, AsyncPageStreaming +from gcore.types.streaming import Restream + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRestreams: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + restream = client.streaming.restreams.create() + assert restream is None + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + restream = client.streaming.restreams.create( + restream={ + "active": True, + "client_user_id": 10, + "live": True, + "name": "first restream", + "stream_id": 20, + "uri": "rtmp://a.rtmp.youtube.com/live/k17a-13s8", + }, + ) + assert restream is None + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.streaming.restreams.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + restream = response.parse() + assert restream is None + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.streaming.restreams.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + restream = response.parse() + assert restream is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + restream = client.streaming.restreams.update( + restream_id=0, + ) + assert_matches_type(Restream, restream, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + restream = client.streaming.restreams.update( + restream_id=0, + restream={ + "active": True, + "client_user_id": 10, + "live": True, + "name": "first restream", + "stream_id": 20, + "uri": "rtmp://a.rtmp.youtube.com/live/k17a-13s8", + }, + ) + assert_matches_type(Restream, restream, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.streaming.restreams.with_raw_response.update( + restream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + restream = response.parse() + assert_matches_type(Restream, restream, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.streaming.restreams.with_streaming_response.update( + restream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + restream = response.parse() + assert_matches_type(Restream, restream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + restream = client.streaming.restreams.list() + assert_matches_type(SyncPageStreaming[Restream], restream, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + restream = client.streaming.restreams.list( + page=0, + ) + assert_matches_type(SyncPageStreaming[Restream], restream, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.streaming.restreams.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + restream = response.parse() + assert_matches_type(SyncPageStreaming[Restream], restream, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.streaming.restreams.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + restream = response.parse() + assert_matches_type(SyncPageStreaming[Restream], restream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + restream = client.streaming.restreams.delete( + 0, + ) + assert restream is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.streaming.restreams.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + restream = response.parse() + assert restream is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.streaming.restreams.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + restream = response.parse() + assert restream is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + restream = client.streaming.restreams.get( + 0, + ) + assert_matches_type(Restream, restream, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.streaming.restreams.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + restream = response.parse() + assert_matches_type(Restream, restream, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.streaming.restreams.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + restream = response.parse() + assert_matches_type(Restream, restream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncRestreams: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + restream = await async_client.streaming.restreams.create() + assert restream is None + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + restream = await async_client.streaming.restreams.create( + restream={ + "active": True, + "client_user_id": 10, + "live": True, + "name": "first restream", + "stream_id": 20, + "uri": "rtmp://a.rtmp.youtube.com/live/k17a-13s8", + }, + ) + assert restream is None + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.restreams.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + restream = await response.parse() + assert restream is None + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.restreams.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + restream = await response.parse() + assert restream is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + restream = await async_client.streaming.restreams.update( + restream_id=0, + ) + assert_matches_type(Restream, restream, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + restream = await async_client.streaming.restreams.update( + restream_id=0, + restream={ + "active": True, + "client_user_id": 10, + "live": True, + "name": "first restream", + "stream_id": 20, + "uri": "rtmp://a.rtmp.youtube.com/live/k17a-13s8", + }, + ) + assert_matches_type(Restream, restream, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.restreams.with_raw_response.update( + restream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + restream = await response.parse() + assert_matches_type(Restream, restream, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.restreams.with_streaming_response.update( + restream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + restream = await response.parse() + assert_matches_type(Restream, restream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + restream = await async_client.streaming.restreams.list() + assert_matches_type(AsyncPageStreaming[Restream], restream, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + restream = await async_client.streaming.restreams.list( + page=0, + ) + assert_matches_type(AsyncPageStreaming[Restream], restream, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.restreams.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + restream = await response.parse() + assert_matches_type(AsyncPageStreaming[Restream], restream, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.restreams.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + restream = await response.parse() + assert_matches_type(AsyncPageStreaming[Restream], restream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + restream = await async_client.streaming.restreams.delete( + 0, + ) + assert restream is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.restreams.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + restream = await response.parse() + assert restream is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.restreams.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + restream = await response.parse() + assert restream is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + restream = await async_client.streaming.restreams.get( + 0, + ) + assert_matches_type(Restream, restream, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.restreams.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + restream = await response.parse() + assert_matches_type(Restream, restream, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.restreams.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + restream = await response.parse() + assert_matches_type(Restream, restream, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/streaming/test_statistics.py b/tests/api_resources/streaming/test_statistics.py new file mode 100644 index 00000000..35093360 --- /dev/null +++ b/tests/api_resources/streaming/test_statistics.py @@ -0,0 +1,1860 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.streaming import ( + Views, + Ffprobes, + StreamSeries, + ViewsHeatmap, + PopularVideos, + StorageSeries, + UniqueViewers, + ViewsByRegion, + ViewsByBrowser, + ViewsByCountry, + ViewsByReferer, + MaxStreamSeries, + ViewsByHostname, + UniqueViewersCDN, + VodStatisticsSeries, + ViewsByOperatingSystem, + VodTotalStreamDurationSeries, + StatisticGetLiveUniqueViewersResponse, + StatisticGetVodWatchTimeTotalCDNResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestStatistics: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_ffprobes(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_ffprobes( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + ) + assert_matches_type(Ffprobes, statistic, path=["response"]) + + @parametrize + def test_method_get_ffprobes_with_all_params(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_ffprobes( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + interval=0, + units="second", + ) + assert_matches_type(Ffprobes, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_ffprobes(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_ffprobes( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(Ffprobes, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_ffprobes(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_ffprobes( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(Ffprobes, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_live_unique_viewers(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_live_unique_viewers( + from_="from", + to="to", + ) + assert_matches_type(StatisticGetLiveUniqueViewersResponse, statistic, path=["response"]) + + @parametrize + def test_method_get_live_unique_viewers_with_all_params(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_live_unique_viewers( + from_="from", + to="to", + client_user_id=0, + granularity="1m", + stream_id=0, + ) + assert_matches_type(StatisticGetLiveUniqueViewersResponse, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_live_unique_viewers(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_live_unique_viewers( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(StatisticGetLiveUniqueViewersResponse, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_live_unique_viewers(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_live_unique_viewers( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(StatisticGetLiveUniqueViewersResponse, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_live_watch_time_cdn(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_live_watch_time_cdn( + from_="from", + ) + assert_matches_type(StreamSeries, statistic, path=["response"]) + + @parametrize + def test_method_get_live_watch_time_cdn_with_all_params(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_live_watch_time_cdn( + from_="from", + client_user_id=0, + granularity="1m", + stream_id=0, + to="to", + ) + assert_matches_type(StreamSeries, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_live_watch_time_cdn(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_live_watch_time_cdn( + from_="from", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(StreamSeries, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_live_watch_time_cdn(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_live_watch_time_cdn( + from_="from", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(StreamSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_live_watch_time_total_cdn(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_live_watch_time_total_cdn() + assert_matches_type(VodTotalStreamDurationSeries, statistic, path=["response"]) + + @parametrize + def test_method_get_live_watch_time_total_cdn_with_all_params(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_live_watch_time_total_cdn( + client_user_id=0, + from_="from", + stream_id=0, + to="to", + ) + assert_matches_type(VodTotalStreamDurationSeries, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_live_watch_time_total_cdn(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_live_watch_time_total_cdn() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(VodTotalStreamDurationSeries, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_live_watch_time_total_cdn(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_live_watch_time_total_cdn() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(VodTotalStreamDurationSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_max_streams_series(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_max_streams_series( + from_="from", + to="to", + ) + assert_matches_type(MaxStreamSeries, statistic, path=["response"]) + + @parametrize + def test_method_get_max_streams_series_with_all_params(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_max_streams_series( + from_="from", + to="to", + granularity="1m", + ) + assert_matches_type(MaxStreamSeries, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_max_streams_series(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_max_streams_series( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(MaxStreamSeries, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_max_streams_series(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_max_streams_series( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(MaxStreamSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_popular_videos(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_popular_videos( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(PopularVideos, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_popular_videos(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_popular_videos( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(PopularVideos, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_popular_videos(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_popular_videos( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(PopularVideos, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_storage_series(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_storage_series( + from_="from", + to="to", + ) + assert_matches_type(StorageSeries, statistic, path=["response"]) + + @parametrize + def test_method_get_storage_series_with_all_params(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_storage_series( + from_="from", + to="to", + granularity="1m", + ) + assert_matches_type(StorageSeries, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_storage_series(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_storage_series( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(StorageSeries, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_storage_series(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_storage_series( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(StorageSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_stream_series(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_stream_series( + from_="from", + to="to", + ) + assert_matches_type(StreamSeries, statistic, path=["response"]) + + @parametrize + def test_method_get_stream_series_with_all_params(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_stream_series( + from_="from", + to="to", + granularity="1m", + ) + assert_matches_type(StreamSeries, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_stream_series(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_stream_series( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(StreamSeries, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_stream_series(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_stream_series( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(StreamSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_unique_viewers(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_unique_viewers( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(UniqueViewers, statistic, path=["response"]) + + @parametrize + def test_method_get_unique_viewers_with_all_params(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_unique_viewers( + date_from="date_from", + date_to="date_to", + id="id", + country="country", + event="init", + group=["date"], + host="host", + type="live", + ) + assert_matches_type(UniqueViewers, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_unique_viewers(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_unique_viewers( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(UniqueViewers, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_unique_viewers(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_unique_viewers( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(UniqueViewers, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_unique_viewers_cdn(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_unique_viewers_cdn( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(UniqueViewersCDN, statistic, path=["response"]) + + @parametrize + def test_method_get_unique_viewers_cdn_with_all_params(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_unique_viewers_cdn( + date_from="date_from", + date_to="date_to", + id="id", + type="live", + ) + assert_matches_type(UniqueViewersCDN, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_unique_viewers_cdn(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_unique_viewers_cdn( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(UniqueViewersCDN, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_unique_viewers_cdn(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_unique_viewers_cdn( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(UniqueViewersCDN, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_views(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_views( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(Views, statistic, path=["response"]) + + @parametrize + def test_method_get_views_with_all_params(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_views( + date_from="date_from", + date_to="date_to", + id="id", + country="country", + event="init", + group=["host"], + host="host", + type="live", + ) + assert_matches_type(Views, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_views(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_views( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(Views, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_views(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_views( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(Views, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_views_by_browsers(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_views_by_browsers( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(ViewsByBrowser, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_views_by_browsers(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_views_by_browsers( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(ViewsByBrowser, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_views_by_browsers(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_views_by_browsers( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(ViewsByBrowser, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_views_by_country(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_views_by_country( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(ViewsByCountry, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_views_by_country(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_views_by_country( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(ViewsByCountry, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_views_by_country(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_views_by_country( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(ViewsByCountry, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_views_by_hostname(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_views_by_hostname( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(ViewsByHostname, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_views_by_hostname(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_views_by_hostname( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(ViewsByHostname, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_views_by_hostname(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_views_by_hostname( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(ViewsByHostname, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_views_by_operating_system(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_views_by_operating_system( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(ViewsByOperatingSystem, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_views_by_operating_system(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_views_by_operating_system( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(ViewsByOperatingSystem, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_views_by_operating_system(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_views_by_operating_system( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(ViewsByOperatingSystem, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_views_by_referer(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_views_by_referer( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(ViewsByReferer, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_views_by_referer(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_views_by_referer( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(ViewsByReferer, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_views_by_referer(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_views_by_referer( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(ViewsByReferer, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_views_by_region(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_views_by_region( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(ViewsByRegion, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_views_by_region(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_views_by_region( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(ViewsByRegion, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_views_by_region(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_views_by_region( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(ViewsByRegion, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_views_heatmap(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_views_heatmap( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + type="live", + ) + assert_matches_type(ViewsHeatmap, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_views_heatmap(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_views_heatmap( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + type="live", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(ViewsHeatmap, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_views_heatmap(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_views_heatmap( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + type="live", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(ViewsHeatmap, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_vod_storage_volume(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_vod_storage_volume( + from_="from", + to="to", + ) + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_vod_storage_volume(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_vod_storage_volume( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_vod_storage_volume(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_vod_storage_volume( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_vod_transcoding_duration(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_vod_transcoding_duration( + from_="from", + to="to", + ) + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_vod_transcoding_duration(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_vod_transcoding_duration( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_vod_transcoding_duration(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_vod_transcoding_duration( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_vod_unique_viewers_cdn(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_vod_unique_viewers_cdn( + from_="from", + to="to", + ) + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + def test_method_get_vod_unique_viewers_cdn_with_all_params(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_vod_unique_viewers_cdn( + from_="from", + to="to", + client_user_id=0, + granularity="1m", + slug="slug", + ) + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_vod_unique_viewers_cdn(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_vod_unique_viewers_cdn( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_vod_unique_viewers_cdn(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_vod_unique_viewers_cdn( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_vod_watch_time_cdn(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_vod_watch_time_cdn( + from_="from", + ) + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + def test_method_get_vod_watch_time_cdn_with_all_params(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_vod_watch_time_cdn( + from_="from", + client_user_id=0, + granularity="1m", + slug="slug", + to="to", + ) + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_vod_watch_time_cdn(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_vod_watch_time_cdn( + from_="from", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_vod_watch_time_cdn(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_vod_watch_time_cdn( + from_="from", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_vod_watch_time_total_cdn(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_vod_watch_time_total_cdn() + assert_matches_type(StatisticGetVodWatchTimeTotalCDNResponse, statistic, path=["response"]) + + @parametrize + def test_method_get_vod_watch_time_total_cdn_with_all_params(self, client: Gcore) -> None: + statistic = client.streaming.statistics.get_vod_watch_time_total_cdn( + client_user_id=0, + from_="from", + slug="slug", + to="to", + ) + assert_matches_type(StatisticGetVodWatchTimeTotalCDNResponse, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_vod_watch_time_total_cdn(self, client: Gcore) -> None: + response = client.streaming.statistics.with_raw_response.get_vod_watch_time_total_cdn() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(StatisticGetVodWatchTimeTotalCDNResponse, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_vod_watch_time_total_cdn(self, client: Gcore) -> None: + with client.streaming.statistics.with_streaming_response.get_vod_watch_time_total_cdn() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(StatisticGetVodWatchTimeTotalCDNResponse, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncStatistics: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_ffprobes(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_ffprobes( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + ) + assert_matches_type(Ffprobes, statistic, path=["response"]) + + @parametrize + async def test_method_get_ffprobes_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_ffprobes( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + interval=0, + units="second", + ) + assert_matches_type(Ffprobes, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_ffprobes(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_ffprobes( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(Ffprobes, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_ffprobes(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_ffprobes( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(Ffprobes, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_live_unique_viewers(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_live_unique_viewers( + from_="from", + to="to", + ) + assert_matches_type(StatisticGetLiveUniqueViewersResponse, statistic, path=["response"]) + + @parametrize + async def test_method_get_live_unique_viewers_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_live_unique_viewers( + from_="from", + to="to", + client_user_id=0, + granularity="1m", + stream_id=0, + ) + assert_matches_type(StatisticGetLiveUniqueViewersResponse, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_live_unique_viewers(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_live_unique_viewers( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(StatisticGetLiveUniqueViewersResponse, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_live_unique_viewers(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_live_unique_viewers( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(StatisticGetLiveUniqueViewersResponse, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_live_watch_time_cdn(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_live_watch_time_cdn( + from_="from", + ) + assert_matches_type(StreamSeries, statistic, path=["response"]) + + @parametrize + async def test_method_get_live_watch_time_cdn_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_live_watch_time_cdn( + from_="from", + client_user_id=0, + granularity="1m", + stream_id=0, + to="to", + ) + assert_matches_type(StreamSeries, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_live_watch_time_cdn(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_live_watch_time_cdn( + from_="from", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(StreamSeries, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_live_watch_time_cdn(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_live_watch_time_cdn( + from_="from", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(StreamSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_live_watch_time_total_cdn(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_live_watch_time_total_cdn() + assert_matches_type(VodTotalStreamDurationSeries, statistic, path=["response"]) + + @parametrize + async def test_method_get_live_watch_time_total_cdn_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_live_watch_time_total_cdn( + client_user_id=0, + from_="from", + stream_id=0, + to="to", + ) + assert_matches_type(VodTotalStreamDurationSeries, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_live_watch_time_total_cdn(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_live_watch_time_total_cdn() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(VodTotalStreamDurationSeries, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_live_watch_time_total_cdn(self, async_client: AsyncGcore) -> None: + async with ( + async_client.streaming.statistics.with_streaming_response.get_live_watch_time_total_cdn() + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(VodTotalStreamDurationSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_max_streams_series(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_max_streams_series( + from_="from", + to="to", + ) + assert_matches_type(MaxStreamSeries, statistic, path=["response"]) + + @parametrize + async def test_method_get_max_streams_series_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_max_streams_series( + from_="from", + to="to", + granularity="1m", + ) + assert_matches_type(MaxStreamSeries, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_max_streams_series(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_max_streams_series( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(MaxStreamSeries, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_max_streams_series(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_max_streams_series( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(MaxStreamSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_popular_videos(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_popular_videos( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(PopularVideos, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_popular_videos(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_popular_videos( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(PopularVideos, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_popular_videos(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_popular_videos( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(PopularVideos, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_storage_series(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_storage_series( + from_="from", + to="to", + ) + assert_matches_type(StorageSeries, statistic, path=["response"]) + + @parametrize + async def test_method_get_storage_series_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_storage_series( + from_="from", + to="to", + granularity="1m", + ) + assert_matches_type(StorageSeries, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_storage_series(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_storage_series( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(StorageSeries, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_storage_series(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_storage_series( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(StorageSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_stream_series(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_stream_series( + from_="from", + to="to", + ) + assert_matches_type(StreamSeries, statistic, path=["response"]) + + @parametrize + async def test_method_get_stream_series_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_stream_series( + from_="from", + to="to", + granularity="1m", + ) + assert_matches_type(StreamSeries, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_stream_series(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_stream_series( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(StreamSeries, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_stream_series(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_stream_series( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(StreamSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_unique_viewers(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_unique_viewers( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(UniqueViewers, statistic, path=["response"]) + + @parametrize + async def test_method_get_unique_viewers_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_unique_viewers( + date_from="date_from", + date_to="date_to", + id="id", + country="country", + event="init", + group=["date"], + host="host", + type="live", + ) + assert_matches_type(UniqueViewers, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_unique_viewers(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_unique_viewers( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(UniqueViewers, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_unique_viewers(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_unique_viewers( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(UniqueViewers, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_unique_viewers_cdn(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_unique_viewers_cdn( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(UniqueViewersCDN, statistic, path=["response"]) + + @parametrize + async def test_method_get_unique_viewers_cdn_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_unique_viewers_cdn( + date_from="date_from", + date_to="date_to", + id="id", + type="live", + ) + assert_matches_type(UniqueViewersCDN, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_unique_viewers_cdn(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_unique_viewers_cdn( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(UniqueViewersCDN, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_unique_viewers_cdn(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_unique_viewers_cdn( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(UniqueViewersCDN, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_views(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_views( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(Views, statistic, path=["response"]) + + @parametrize + async def test_method_get_views_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_views( + date_from="date_from", + date_to="date_to", + id="id", + country="country", + event="init", + group=["host"], + host="host", + type="live", + ) + assert_matches_type(Views, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_views(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_views( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(Views, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_views(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_views( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(Views, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_views_by_browsers(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_views_by_browsers( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(ViewsByBrowser, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_views_by_browsers(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_views_by_browsers( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(ViewsByBrowser, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_views_by_browsers(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_views_by_browsers( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(ViewsByBrowser, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_views_by_country(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_views_by_country( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(ViewsByCountry, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_views_by_country(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_views_by_country( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(ViewsByCountry, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_views_by_country(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_views_by_country( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(ViewsByCountry, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_views_by_hostname(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_views_by_hostname( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(ViewsByHostname, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_views_by_hostname(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_views_by_hostname( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(ViewsByHostname, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_views_by_hostname(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_views_by_hostname( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(ViewsByHostname, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_views_by_operating_system(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_views_by_operating_system( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(ViewsByOperatingSystem, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_views_by_operating_system(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_views_by_operating_system( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(ViewsByOperatingSystem, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_views_by_operating_system(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_views_by_operating_system( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(ViewsByOperatingSystem, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_views_by_referer(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_views_by_referer( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(ViewsByReferer, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_views_by_referer(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_views_by_referer( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(ViewsByReferer, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_views_by_referer(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_views_by_referer( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(ViewsByReferer, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_views_by_region(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_views_by_region( + date_from="date_from", + date_to="date_to", + ) + assert_matches_type(ViewsByRegion, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_views_by_region(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_views_by_region( + date_from="date_from", + date_to="date_to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(ViewsByRegion, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_views_by_region(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_views_by_region( + date_from="date_from", + date_to="date_to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(ViewsByRegion, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_views_heatmap(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_views_heatmap( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + type="live", + ) + assert_matches_type(ViewsHeatmap, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_views_heatmap(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_views_heatmap( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + type="live", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(ViewsHeatmap, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_views_heatmap(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_views_heatmap( + date_from="date_from", + date_to="date_to", + stream_id="stream_id", + type="live", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(ViewsHeatmap, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_vod_storage_volume(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_vod_storage_volume( + from_="from", + to="to", + ) + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_vod_storage_volume(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_vod_storage_volume( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_vod_storage_volume(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_vod_storage_volume( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_vod_transcoding_duration(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_vod_transcoding_duration( + from_="from", + to="to", + ) + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_vod_transcoding_duration(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_vod_transcoding_duration( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_vod_transcoding_duration(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_vod_transcoding_duration( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_vod_unique_viewers_cdn(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_vod_unique_viewers_cdn( + from_="from", + to="to", + ) + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + async def test_method_get_vod_unique_viewers_cdn_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_vod_unique_viewers_cdn( + from_="from", + to="to", + client_user_id=0, + granularity="1m", + slug="slug", + ) + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_vod_unique_viewers_cdn(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_vod_unique_viewers_cdn( + from_="from", + to="to", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_vod_unique_viewers_cdn(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_vod_unique_viewers_cdn( + from_="from", + to="to", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_vod_watch_time_cdn(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_vod_watch_time_cdn( + from_="from", + ) + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + async def test_method_get_vod_watch_time_cdn_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_vod_watch_time_cdn( + from_="from", + client_user_id=0, + granularity="1m", + slug="slug", + to="to", + ) + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_vod_watch_time_cdn(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_vod_watch_time_cdn( + from_="from", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_vod_watch_time_cdn(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_vod_watch_time_cdn( + from_="from", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(VodStatisticsSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_vod_watch_time_total_cdn(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_vod_watch_time_total_cdn() + assert_matches_type(StatisticGetVodWatchTimeTotalCDNResponse, statistic, path=["response"]) + + @parametrize + async def test_method_get_vod_watch_time_total_cdn_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.streaming.statistics.get_vod_watch_time_total_cdn( + client_user_id=0, + from_="from", + slug="slug", + to="to", + ) + assert_matches_type(StatisticGetVodWatchTimeTotalCDNResponse, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_vod_watch_time_total_cdn(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.statistics.with_raw_response.get_vod_watch_time_total_cdn() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(StatisticGetVodWatchTimeTotalCDNResponse, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_vod_watch_time_total_cdn(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.statistics.with_streaming_response.get_vod_watch_time_total_cdn() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(StatisticGetVodWatchTimeTotalCDNResponse, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/streaming/test_streams.py b/tests/api_resources/streaming/test_streams.py new file mode 100644 index 00000000..dfe61205 --- /dev/null +++ b/tests/api_resources/streaming/test_streams.py @@ -0,0 +1,777 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncPageStreaming, AsyncPageStreaming +from gcore.types.streaming import ( + Clip, + Video, + Stream, + StreamListClipsResponse, + StreamStartRecordingResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestStreams: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + stream = client.streaming.streams.create( + name="Live stream by user e4d0f942-f35d", + ) + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + stream = client.streaming.streams.create( + name="Live stream by user e4d0f942-f35d", + active=True, + auto_record=False, + broadcast_ids=[0], + cdn_id=0, + client_entity_data="client_entity_data", + client_user_id=1001, + dvr_duration=0, + dvr_enabled=True, + hls_mpegts_endlist_tag=True, + html_overlay=False, + projection="regular", + pull=True, + quality_set_id=0, + record_type="origin", + uri="srt://domain.com:5000/?streamid=12345", + ) + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.streaming.streams.with_raw_response.create( + name="Live stream by user e4d0f942-f35d", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.streaming.streams.with_streaming_response.create( + name="Live stream by user e4d0f942-f35d", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + assert_matches_type(Stream, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + stream = client.streaming.streams.update( + stream_id=0, + ) + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + stream = client.streaming.streams.update( + stream_id=0, + stream={ + "name": "Live stream by user e4d0f942-f35d", + "active": True, + "auto_record": False, + "broadcast_ids": [0], + "cdn_id": 0, + "client_entity_data": "client_entity_data", + "client_user_id": 1001, + "dvr_duration": 0, + "dvr_enabled": True, + "hls_mpegts_endlist_tag": True, + "html_overlay": False, + "projection": "regular", + "pull": True, + "quality_set_id": 0, + "record_type": "origin", + "uri": "srt://domain.com:5000/?streamid=12345", + }, + ) + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.streaming.streams.with_raw_response.update( + stream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.streaming.streams.with_streaming_response.update( + stream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + assert_matches_type(Stream, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + stream = client.streaming.streams.list() + assert_matches_type(SyncPageStreaming[Stream], stream, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + stream = client.streaming.streams.list( + page=0, + with_broadcasts=0, + ) + assert_matches_type(SyncPageStreaming[Stream], stream, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.streaming.streams.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + assert_matches_type(SyncPageStreaming[Stream], stream, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.streaming.streams.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + assert_matches_type(SyncPageStreaming[Stream], stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + stream = client.streaming.streams.delete( + 0, + ) + assert stream is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.streaming.streams.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + assert stream is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.streaming.streams.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + assert stream is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_clear_dvr(self, client: Gcore) -> None: + stream = client.streaming.streams.clear_dvr( + 0, + ) + assert stream is None + + @parametrize + def test_raw_response_clear_dvr(self, client: Gcore) -> None: + response = client.streaming.streams.with_raw_response.clear_dvr( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + assert stream is None + + @parametrize + def test_streaming_response_clear_dvr(self, client: Gcore) -> None: + with client.streaming.streams.with_streaming_response.clear_dvr( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + assert stream is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_clip(self, client: Gcore) -> None: + stream = client.streaming.streams.create_clip( + stream_id=0, + duration=0, + ) + assert_matches_type(Clip, stream, path=["response"]) + + @parametrize + def test_method_create_clip_with_all_params(self, client: Gcore) -> None: + stream = client.streaming.streams.create_clip( + stream_id=0, + duration=0, + expiration=0, + start=0, + vod_required=True, + ) + assert_matches_type(Clip, stream, path=["response"]) + + @parametrize + def test_raw_response_create_clip(self, client: Gcore) -> None: + response = client.streaming.streams.with_raw_response.create_clip( + stream_id=0, + duration=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + assert_matches_type(Clip, stream, path=["response"]) + + @parametrize + def test_streaming_response_create_clip(self, client: Gcore) -> None: + with client.streaming.streams.with_streaming_response.create_clip( + stream_id=0, + duration=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + assert_matches_type(Clip, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + stream = client.streaming.streams.get( + 0, + ) + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.streaming.streams.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.streaming.streams.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + assert_matches_type(Stream, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_clips(self, client: Gcore) -> None: + stream = client.streaming.streams.list_clips( + 0, + ) + assert_matches_type(StreamListClipsResponse, stream, path=["response"]) + + @parametrize + def test_raw_response_list_clips(self, client: Gcore) -> None: + response = client.streaming.streams.with_raw_response.list_clips( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + assert_matches_type(StreamListClipsResponse, stream, path=["response"]) + + @parametrize + def test_streaming_response_list_clips(self, client: Gcore) -> None: + with client.streaming.streams.with_streaming_response.list_clips( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + assert_matches_type(StreamListClipsResponse, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_start_recording(self, client: Gcore) -> None: + stream = client.streaming.streams.start_recording( + 0, + ) + assert_matches_type(StreamStartRecordingResponse, stream, path=["response"]) + + @parametrize + def test_raw_response_start_recording(self, client: Gcore) -> None: + response = client.streaming.streams.with_raw_response.start_recording( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + assert_matches_type(StreamStartRecordingResponse, stream, path=["response"]) + + @parametrize + def test_streaming_response_start_recording(self, client: Gcore) -> None: + with client.streaming.streams.with_streaming_response.start_recording( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + assert_matches_type(StreamStartRecordingResponse, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_stop_recording(self, client: Gcore) -> None: + stream = client.streaming.streams.stop_recording( + 0, + ) + assert_matches_type(Video, stream, path=["response"]) + + @parametrize + def test_raw_response_stop_recording(self, client: Gcore) -> None: + response = client.streaming.streams.with_raw_response.stop_recording( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + assert_matches_type(Video, stream, path=["response"]) + + @parametrize + def test_streaming_response_stop_recording(self, client: Gcore) -> None: + with client.streaming.streams.with_streaming_response.stop_recording( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + assert_matches_type(Video, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncStreams: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.create( + name="Live stream by user e4d0f942-f35d", + ) + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.create( + name="Live stream by user e4d0f942-f35d", + active=True, + auto_record=False, + broadcast_ids=[0], + cdn_id=0, + client_entity_data="client_entity_data", + client_user_id=1001, + dvr_duration=0, + dvr_enabled=True, + hls_mpegts_endlist_tag=True, + html_overlay=False, + projection="regular", + pull=True, + quality_set_id=0, + record_type="origin", + uri="srt://domain.com:5000/?streamid=12345", + ) + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.with_raw_response.create( + name="Live stream by user e4d0f942-f35d", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = await response.parse() + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.with_streaming_response.create( + name="Live stream by user e4d0f942-f35d", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + assert_matches_type(Stream, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.update( + stream_id=0, + ) + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.update( + stream_id=0, + stream={ + "name": "Live stream by user e4d0f942-f35d", + "active": True, + "auto_record": False, + "broadcast_ids": [0], + "cdn_id": 0, + "client_entity_data": "client_entity_data", + "client_user_id": 1001, + "dvr_duration": 0, + "dvr_enabled": True, + "hls_mpegts_endlist_tag": True, + "html_overlay": False, + "projection": "regular", + "pull": True, + "quality_set_id": 0, + "record_type": "origin", + "uri": "srt://domain.com:5000/?streamid=12345", + }, + ) + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.with_raw_response.update( + stream_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = await response.parse() + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.with_streaming_response.update( + stream_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + assert_matches_type(Stream, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.list() + assert_matches_type(AsyncPageStreaming[Stream], stream, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.list( + page=0, + with_broadcasts=0, + ) + assert_matches_type(AsyncPageStreaming[Stream], stream, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = await response.parse() + assert_matches_type(AsyncPageStreaming[Stream], stream, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + assert_matches_type(AsyncPageStreaming[Stream], stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.delete( + 0, + ) + assert stream is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = await response.parse() + assert stream is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + assert stream is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_clear_dvr(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.clear_dvr( + 0, + ) + assert stream is None + + @parametrize + async def test_raw_response_clear_dvr(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.with_raw_response.clear_dvr( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = await response.parse() + assert stream is None + + @parametrize + async def test_streaming_response_clear_dvr(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.with_streaming_response.clear_dvr( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + assert stream is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_clip(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.create_clip( + stream_id=0, + duration=0, + ) + assert_matches_type(Clip, stream, path=["response"]) + + @parametrize + async def test_method_create_clip_with_all_params(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.create_clip( + stream_id=0, + duration=0, + expiration=0, + start=0, + vod_required=True, + ) + assert_matches_type(Clip, stream, path=["response"]) + + @parametrize + async def test_raw_response_create_clip(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.with_raw_response.create_clip( + stream_id=0, + duration=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = await response.parse() + assert_matches_type(Clip, stream, path=["response"]) + + @parametrize + async def test_streaming_response_create_clip(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.with_streaming_response.create_clip( + stream_id=0, + duration=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + assert_matches_type(Clip, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.get( + 0, + ) + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = await response.parse() + assert_matches_type(Stream, stream, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + assert_matches_type(Stream, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_clips(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.list_clips( + 0, + ) + assert_matches_type(StreamListClipsResponse, stream, path=["response"]) + + @parametrize + async def test_raw_response_list_clips(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.with_raw_response.list_clips( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = await response.parse() + assert_matches_type(StreamListClipsResponse, stream, path=["response"]) + + @parametrize + async def test_streaming_response_list_clips(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.with_streaming_response.list_clips( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + assert_matches_type(StreamListClipsResponse, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_start_recording(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.start_recording( + 0, + ) + assert_matches_type(StreamStartRecordingResponse, stream, path=["response"]) + + @parametrize + async def test_raw_response_start_recording(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.with_raw_response.start_recording( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = await response.parse() + assert_matches_type(StreamStartRecordingResponse, stream, path=["response"]) + + @parametrize + async def test_streaming_response_start_recording(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.with_streaming_response.start_recording( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + assert_matches_type(StreamStartRecordingResponse, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_stop_recording(self, async_client: AsyncGcore) -> None: + stream = await async_client.streaming.streams.stop_recording( + 0, + ) + assert_matches_type(Video, stream, path=["response"]) + + @parametrize + async def test_raw_response_stop_recording(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.streams.with_raw_response.stop_recording( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = await response.parse() + assert_matches_type(Video, stream, path=["response"]) + + @parametrize + async def test_streaming_response_stop_recording(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.streams.with_streaming_response.stop_recording( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + assert_matches_type(Video, stream, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/streaming/test_videos.py b/tests/api_resources/streaming/test_videos.py new file mode 100644 index 00000000..a37fa288 --- /dev/null +++ b/tests/api_resources/streaming/test_videos.py @@ -0,0 +1,722 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncPageStreaming, AsyncPageStreaming +from gcore.types.streaming import ( + Video, + VideoCreateResponse, + DirectUploadParameters, + VideoCreateMultipleResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestVideos: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + video = client.streaming.videos.create() + assert_matches_type(VideoCreateResponse, video, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + video = client.streaming.videos.create( + video={ + "name": "IBC 2025 - International Broadcasting Convention", + "auto_transcribe_audio_language": "auto", + "auto_translate_subtitles_language": "disable", + "client_user_id": 10, + "clip_duration_seconds": 60, + "clip_start_seconds": 137, + "custom_iframe_url": "custom_iframe_url", + "description": "We look forward to welcoming you at IBC2025, which will take place 12-15 September 2025.", + "directory_id": 800, + "origin_http_headers": "Authorization: Bearer ...", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "poster": "data:image/jpeg;base64,/9j/4AA...qf/2Q==", + "priority": 0, + "projection": "regular", + "quality_set_id": 0, + "remote_poster_url": "remote_poster_url", + "remove_poster": True, + "screenshot_id": -1, + "share_url": "share_url", + "source_bitrate_limit": True, + }, + ) + assert_matches_type(VideoCreateResponse, video, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.streaming.videos.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(VideoCreateResponse, video, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.streaming.videos.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(VideoCreateResponse, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + video = client.streaming.videos.update( + video_id=0, + name="IBC 2025 - International Broadcasting Convention", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + video = client.streaming.videos.update( + video_id=0, + name="IBC 2025 - International Broadcasting Convention", + auto_transcribe_audio_language="auto", + auto_translate_subtitles_language="disable", + client_user_id=10, + clip_duration_seconds=60, + clip_start_seconds=137, + custom_iframe_url="custom_iframe_url", + description="We look forward to welcoming you at IBC2025, which will take place 12-15 September 2025.", + directory_id=800, + origin_http_headers="Authorization: Bearer ...", + origin_url="https://www.googleapis.com/drive/v3/files/...?alt=media", + poster="data:image/jpeg;base64,/9j/4AA...qf/2Q==", + priority=0, + projection="regular", + quality_set_id=0, + remote_poster_url="remote_poster_url", + remove_poster=True, + screenshot_id=-1, + share_url="share_url", + source_bitrate_limit=True, + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.streaming.videos.with_raw_response.update( + video_id=0, + name="IBC 2025 - International Broadcasting Convention", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.streaming.videos.with_streaming_response.update( + video_id=0, + name="IBC 2025 - International Broadcasting Convention", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + video = client.streaming.videos.list() + assert_matches_type(SyncPageStreaming[Video], video, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + video = client.streaming.videos.list( + id="id", + client_user_id=0, + fields="fields", + page=0, + per_page=0, + search="search", + status="status", + stream_id=0, + ) + assert_matches_type(SyncPageStreaming[Video], video, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.streaming.videos.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(SyncPageStreaming[Video], video, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.streaming.videos.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(SyncPageStreaming[Video], video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + video = client.streaming.videos.delete( + 0, + ) + assert video is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.streaming.videos.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert video is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.streaming.videos.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert video is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_multiple(self, client: Gcore) -> None: + video = client.streaming.videos.create_multiple() + assert_matches_type(VideoCreateMultipleResponse, video, path=["response"]) + + @parametrize + def test_method_create_multiple_with_all_params(self, client: Gcore) -> None: + video = client.streaming.videos.create_multiple( + fields="fields", + videos=[ + { + "name": "IBC 2025 - International Broadcasting Convention", + "auto_transcribe_audio_language": "auto", + "auto_translate_subtitles_language": "disable", + "client_user_id": 10, + "clip_duration_seconds": 60, + "clip_start_seconds": 137, + "custom_iframe_url": "custom_iframe_url", + "description": "We look forward to welcoming you at IBC2025, which will take place 12-15 September 2025.", + "directory_id": 800, + "origin_http_headers": "Authorization: Bearer ...", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "poster": "data:image/jpeg;base64,/9j/4AA...qf/2Q==", + "priority": 0, + "projection": "regular", + "quality_set_id": 0, + "remote_poster_url": "remote_poster_url", + "remove_poster": True, + "screenshot_id": -1, + "share_url": "share_url", + "source_bitrate_limit": True, + "subtitles": [ + { + "language": "eng", + "vtt": "WEBVTT\n\n1\n00:00:07.154 --> 00:00:12.736\nWe have 100 million registered users or active users who play at least once a week.\n\n2\n00:00:13.236 --> 00:00:20.198\nWe might have 80 or 100,000 playing on a given cluster.", + "name": "English (AI-generated)", + }, + { + "language": "ger", + "vtt": "WEBVTT\n\n1\n00:00:07.154 --> 00:00:12.736\nWir haben 100 Millionen registrierte Benutzer oder aktive Benutzer, die mindestens einmal pro Woche spielen.\n\n2\n00:00:13.236 --> 00:00:20.198\nWir haben vielleicht 80 oder 100.000, die auf einem bestimmten Cluster spielen.", + "name": "German (AI-translated)", + }, + ], + } + ], + ) + assert_matches_type(VideoCreateMultipleResponse, video, path=["response"]) + + @parametrize + def test_raw_response_create_multiple(self, client: Gcore) -> None: + response = client.streaming.videos.with_raw_response.create_multiple() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(VideoCreateMultipleResponse, video, path=["response"]) + + @parametrize + def test_streaming_response_create_multiple(self, client: Gcore) -> None: + with client.streaming.videos.with_streaming_response.create_multiple() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(VideoCreateMultipleResponse, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + video = client.streaming.videos.get( + 0, + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.streaming.videos.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.streaming.videos.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_parameters_for_direct_upload(self, client: Gcore) -> None: + video = client.streaming.videos.get_parameters_for_direct_upload( + 0, + ) + assert_matches_type(DirectUploadParameters, video, path=["response"]) + + @parametrize + def test_raw_response_get_parameters_for_direct_upload(self, client: Gcore) -> None: + response = client.streaming.videos.with_raw_response.get_parameters_for_direct_upload( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert_matches_type(DirectUploadParameters, video, path=["response"]) + + @parametrize + def test_streaming_response_get_parameters_for_direct_upload(self, client: Gcore) -> None: + with client.streaming.videos.with_streaming_response.get_parameters_for_direct_upload( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert_matches_type(DirectUploadParameters, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_names(self, client: Gcore) -> None: + video = client.streaming.videos.list_names() + assert video is None + + @parametrize + def test_method_list_names_with_all_params(self, client: Gcore) -> None: + video = client.streaming.videos.list_names( + ids=[0], + ) + assert video is None + + @parametrize + def test_raw_response_list_names(self, client: Gcore) -> None: + response = client.streaming.videos.with_raw_response.list_names() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = response.parse() + assert video is None + + @parametrize + def test_streaming_response_list_names(self, client: Gcore) -> None: + with client.streaming.videos.with_streaming_response.list_names() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = response.parse() + assert video is None + + assert cast(Any, response.is_closed) is True + + +class TestAsyncVideos: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + video = await async_client.streaming.videos.create() + assert_matches_type(VideoCreateResponse, video, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + video = await async_client.streaming.videos.create( + video={ + "name": "IBC 2025 - International Broadcasting Convention", + "auto_transcribe_audio_language": "auto", + "auto_translate_subtitles_language": "disable", + "client_user_id": 10, + "clip_duration_seconds": 60, + "clip_start_seconds": 137, + "custom_iframe_url": "custom_iframe_url", + "description": "We look forward to welcoming you at IBC2025, which will take place 12-15 September 2025.", + "directory_id": 800, + "origin_http_headers": "Authorization: Bearer ...", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "poster": "data:image/jpeg;base64,/9j/4AA...qf/2Q==", + "priority": 0, + "projection": "regular", + "quality_set_id": 0, + "remote_poster_url": "remote_poster_url", + "remove_poster": True, + "screenshot_id": -1, + "share_url": "share_url", + "source_bitrate_limit": True, + }, + ) + assert_matches_type(VideoCreateResponse, video, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.videos.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = await response.parse() + assert_matches_type(VideoCreateResponse, video, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.videos.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(VideoCreateResponse, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + video = await async_client.streaming.videos.update( + video_id=0, + name="IBC 2025 - International Broadcasting Convention", + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + video = await async_client.streaming.videos.update( + video_id=0, + name="IBC 2025 - International Broadcasting Convention", + auto_transcribe_audio_language="auto", + auto_translate_subtitles_language="disable", + client_user_id=10, + clip_duration_seconds=60, + clip_start_seconds=137, + custom_iframe_url="custom_iframe_url", + description="We look forward to welcoming you at IBC2025, which will take place 12-15 September 2025.", + directory_id=800, + origin_http_headers="Authorization: Bearer ...", + origin_url="https://www.googleapis.com/drive/v3/files/...?alt=media", + poster="data:image/jpeg;base64,/9j/4AA...qf/2Q==", + priority=0, + projection="regular", + quality_set_id=0, + remote_poster_url="remote_poster_url", + remove_poster=True, + screenshot_id=-1, + share_url="share_url", + source_bitrate_limit=True, + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.videos.with_raw_response.update( + video_id=0, + name="IBC 2025 - International Broadcasting Convention", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = await response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.videos.with_streaming_response.update( + video_id=0, + name="IBC 2025 - International Broadcasting Convention", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + video = await async_client.streaming.videos.list() + assert_matches_type(AsyncPageStreaming[Video], video, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + video = await async_client.streaming.videos.list( + id="id", + client_user_id=0, + fields="fields", + page=0, + per_page=0, + search="search", + status="status", + stream_id=0, + ) + assert_matches_type(AsyncPageStreaming[Video], video, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.videos.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = await response.parse() + assert_matches_type(AsyncPageStreaming[Video], video, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.videos.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(AsyncPageStreaming[Video], video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + video = await async_client.streaming.videos.delete( + 0, + ) + assert video is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.videos.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = await response.parse() + assert video is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.videos.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert video is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_multiple(self, async_client: AsyncGcore) -> None: + video = await async_client.streaming.videos.create_multiple() + assert_matches_type(VideoCreateMultipleResponse, video, path=["response"]) + + @parametrize + async def test_method_create_multiple_with_all_params(self, async_client: AsyncGcore) -> None: + video = await async_client.streaming.videos.create_multiple( + fields="fields", + videos=[ + { + "name": "IBC 2025 - International Broadcasting Convention", + "auto_transcribe_audio_language": "auto", + "auto_translate_subtitles_language": "disable", + "client_user_id": 10, + "clip_duration_seconds": 60, + "clip_start_seconds": 137, + "custom_iframe_url": "custom_iframe_url", + "description": "We look forward to welcoming you at IBC2025, which will take place 12-15 September 2025.", + "directory_id": 800, + "origin_http_headers": "Authorization: Bearer ...", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "poster": "data:image/jpeg;base64,/9j/4AA...qf/2Q==", + "priority": 0, + "projection": "regular", + "quality_set_id": 0, + "remote_poster_url": "remote_poster_url", + "remove_poster": True, + "screenshot_id": -1, + "share_url": "share_url", + "source_bitrate_limit": True, + "subtitles": [ + { + "language": "eng", + "vtt": "WEBVTT\n\n1\n00:00:07.154 --> 00:00:12.736\nWe have 100 million registered users or active users who play at least once a week.\n\n2\n00:00:13.236 --> 00:00:20.198\nWe might have 80 or 100,000 playing on a given cluster.", + "name": "English (AI-generated)", + }, + { + "language": "ger", + "vtt": "WEBVTT\n\n1\n00:00:07.154 --> 00:00:12.736\nWir haben 100 Millionen registrierte Benutzer oder aktive Benutzer, die mindestens einmal pro Woche spielen.\n\n2\n00:00:13.236 --> 00:00:20.198\nWir haben vielleicht 80 oder 100.000, die auf einem bestimmten Cluster spielen.", + "name": "German (AI-translated)", + }, + ], + } + ], + ) + assert_matches_type(VideoCreateMultipleResponse, video, path=["response"]) + + @parametrize + async def test_raw_response_create_multiple(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.videos.with_raw_response.create_multiple() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = await response.parse() + assert_matches_type(VideoCreateMultipleResponse, video, path=["response"]) + + @parametrize + async def test_streaming_response_create_multiple(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.videos.with_streaming_response.create_multiple() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(VideoCreateMultipleResponse, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + video = await async_client.streaming.videos.get( + 0, + ) + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.videos.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = await response.parse() + assert_matches_type(Video, video, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.videos.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(Video, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_parameters_for_direct_upload(self, async_client: AsyncGcore) -> None: + video = await async_client.streaming.videos.get_parameters_for_direct_upload( + 0, + ) + assert_matches_type(DirectUploadParameters, video, path=["response"]) + + @parametrize + async def test_raw_response_get_parameters_for_direct_upload(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.videos.with_raw_response.get_parameters_for_direct_upload( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = await response.parse() + assert_matches_type(DirectUploadParameters, video, path=["response"]) + + @parametrize + async def test_streaming_response_get_parameters_for_direct_upload(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.videos.with_streaming_response.get_parameters_for_direct_upload( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert_matches_type(DirectUploadParameters, video, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_names(self, async_client: AsyncGcore) -> None: + video = await async_client.streaming.videos.list_names() + assert video is None + + @parametrize + async def test_method_list_names_with_all_params(self, async_client: AsyncGcore) -> None: + video = await async_client.streaming.videos.list_names( + ids=[0], + ) + assert video is None + + @parametrize + async def test_raw_response_list_names(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.videos.with_raw_response.list_names() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + video = await response.parse() + assert video is None + + @parametrize + async def test_streaming_response_list_names(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.videos.with_streaming_response.list_names() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + video = await response.parse() + assert video is None + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/streaming/videos/__init__.py b/tests/api_resources/streaming/videos/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/streaming/videos/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/streaming/videos/test_subtitles.py b/tests/api_resources/streaming/videos/test_subtitles.py new file mode 100644 index 00000000..8997ab5b --- /dev/null +++ b/tests/api_resources/streaming/videos/test_subtitles.py @@ -0,0 +1,409 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.streaming import Subtitle, SubtitleBase +from gcore.types.streaming.videos import SubtitleListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSubtitles: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + subtitle = client.streaming.videos.subtitles.create( + video_id=0, + body={}, + ) + assert_matches_type(Subtitle, subtitle, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + subtitle = client.streaming.videos.subtitles.create( + video_id=0, + body={ + "language": "language", + "name": "German (AI-generated)", + "vtt": "WEBVTT\n\n1\n00:00:07.154 --> 00:00:12.736\nWir haben 100 Millionen registrierte Benutzer oder aktive Benutzer, die mindestens einmal pro Woche spielen.\n\n2\n00:00:13.236 --> 00:00:20.198\nWir haben vielleicht 80 oder 100.000, die auf einem bestimmten Cluster spielen.", + "auto_transcribe_audio_language": "auto", + "auto_translate_subtitles_language": "default", + }, + ) + assert_matches_type(Subtitle, subtitle, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.streaming.videos.subtitles.with_raw_response.create( + video_id=0, + body={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subtitle = response.parse() + assert_matches_type(Subtitle, subtitle, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.streaming.videos.subtitles.with_streaming_response.create( + video_id=0, + body={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subtitle = response.parse() + assert_matches_type(Subtitle, subtitle, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + subtitle = client.streaming.videos.subtitles.update( + id=0, + video_id=0, + ) + assert_matches_type(SubtitleBase, subtitle, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + subtitle = client.streaming.videos.subtitles.update( + id=0, + video_id=0, + language="ltz", + name="name", + vtt="vtt", + ) + assert_matches_type(SubtitleBase, subtitle, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.streaming.videos.subtitles.with_raw_response.update( + id=0, + video_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subtitle = response.parse() + assert_matches_type(SubtitleBase, subtitle, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.streaming.videos.subtitles.with_streaming_response.update( + id=0, + video_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subtitle = response.parse() + assert_matches_type(SubtitleBase, subtitle, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + subtitle = client.streaming.videos.subtitles.list( + 0, + ) + assert_matches_type(SubtitleListResponse, subtitle, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.streaming.videos.subtitles.with_raw_response.list( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subtitle = response.parse() + assert_matches_type(SubtitleListResponse, subtitle, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.streaming.videos.subtitles.with_streaming_response.list( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subtitle = response.parse() + assert_matches_type(SubtitleListResponse, subtitle, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + subtitle = client.streaming.videos.subtitles.delete( + id=0, + video_id=0, + ) + assert subtitle is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.streaming.videos.subtitles.with_raw_response.delete( + id=0, + video_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subtitle = response.parse() + assert subtitle is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.streaming.videos.subtitles.with_streaming_response.delete( + id=0, + video_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subtitle = response.parse() + assert subtitle is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + subtitle = client.streaming.videos.subtitles.get( + id=0, + video_id=0, + ) + assert_matches_type(Subtitle, subtitle, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.streaming.videos.subtitles.with_raw_response.get( + id=0, + video_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subtitle = response.parse() + assert_matches_type(Subtitle, subtitle, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.streaming.videos.subtitles.with_streaming_response.get( + id=0, + video_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subtitle = response.parse() + assert_matches_type(Subtitle, subtitle, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncSubtitles: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + subtitle = await async_client.streaming.videos.subtitles.create( + video_id=0, + body={}, + ) + assert_matches_type(Subtitle, subtitle, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + subtitle = await async_client.streaming.videos.subtitles.create( + video_id=0, + body={ + "language": "language", + "name": "German (AI-generated)", + "vtt": "WEBVTT\n\n1\n00:00:07.154 --> 00:00:12.736\nWir haben 100 Millionen registrierte Benutzer oder aktive Benutzer, die mindestens einmal pro Woche spielen.\n\n2\n00:00:13.236 --> 00:00:20.198\nWir haben vielleicht 80 oder 100.000, die auf einem bestimmten Cluster spielen.", + "auto_transcribe_audio_language": "auto", + "auto_translate_subtitles_language": "default", + }, + ) + assert_matches_type(Subtitle, subtitle, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.videos.subtitles.with_raw_response.create( + video_id=0, + body={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subtitle = await response.parse() + assert_matches_type(Subtitle, subtitle, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.videos.subtitles.with_streaming_response.create( + video_id=0, + body={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subtitle = await response.parse() + assert_matches_type(Subtitle, subtitle, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + subtitle = await async_client.streaming.videos.subtitles.update( + id=0, + video_id=0, + ) + assert_matches_type(SubtitleBase, subtitle, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + subtitle = await async_client.streaming.videos.subtitles.update( + id=0, + video_id=0, + language="ltz", + name="name", + vtt="vtt", + ) + assert_matches_type(SubtitleBase, subtitle, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.videos.subtitles.with_raw_response.update( + id=0, + video_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subtitle = await response.parse() + assert_matches_type(SubtitleBase, subtitle, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.videos.subtitles.with_streaming_response.update( + id=0, + video_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subtitle = await response.parse() + assert_matches_type(SubtitleBase, subtitle, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + subtitle = await async_client.streaming.videos.subtitles.list( + 0, + ) + assert_matches_type(SubtitleListResponse, subtitle, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.videos.subtitles.with_raw_response.list( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subtitle = await response.parse() + assert_matches_type(SubtitleListResponse, subtitle, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.videos.subtitles.with_streaming_response.list( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subtitle = await response.parse() + assert_matches_type(SubtitleListResponse, subtitle, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + subtitle = await async_client.streaming.videos.subtitles.delete( + id=0, + video_id=0, + ) + assert subtitle is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.videos.subtitles.with_raw_response.delete( + id=0, + video_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subtitle = await response.parse() + assert subtitle is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.videos.subtitles.with_streaming_response.delete( + id=0, + video_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subtitle = await response.parse() + assert subtitle is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + subtitle = await async_client.streaming.videos.subtitles.get( + id=0, + video_id=0, + ) + assert_matches_type(Subtitle, subtitle, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.streaming.videos.subtitles.with_raw_response.get( + id=0, + video_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subtitle = await response.parse() + assert_matches_type(Subtitle, subtitle, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.streaming.videos.subtitles.with_streaming_response.get( + id=0, + video_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subtitle = await response.parse() + assert_matches_type(Subtitle, subtitle, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_cdn.py b/tests/api_resources/test_cdn.py new file mode 100644 index 00000000..153a1094 --- /dev/null +++ b/tests/api_resources/test_cdn.py @@ -0,0 +1,421 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.cdn import ( + AwsRegions, + CDNAccount, + AlibabaRegions, + CDNAccountLimits, + CDNAvailableFeatures, + CDNListPurgeStatusesResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCDN: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_account_limits(self, client: Gcore) -> None: + cdn = client.cdn.get_account_limits() + assert_matches_type(CDNAccountLimits, cdn, path=["response"]) + + @parametrize + def test_raw_response_get_account_limits(self, client: Gcore) -> None: + response = client.cdn.with_raw_response.get_account_limits() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = response.parse() + assert_matches_type(CDNAccountLimits, cdn, path=["response"]) + + @parametrize + def test_streaming_response_get_account_limits(self, client: Gcore) -> None: + with client.cdn.with_streaming_response.get_account_limits() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = response.parse() + assert_matches_type(CDNAccountLimits, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_account_overview(self, client: Gcore) -> None: + cdn = client.cdn.get_account_overview() + assert_matches_type(CDNAccount, cdn, path=["response"]) + + @parametrize + def test_raw_response_get_account_overview(self, client: Gcore) -> None: + response = client.cdn.with_raw_response.get_account_overview() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = response.parse() + assert_matches_type(CDNAccount, cdn, path=["response"]) + + @parametrize + def test_streaming_response_get_account_overview(self, client: Gcore) -> None: + with client.cdn.with_streaming_response.get_account_overview() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = response.parse() + assert_matches_type(CDNAccount, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_available_features(self, client: Gcore) -> None: + cdn = client.cdn.get_available_features() + assert_matches_type(CDNAvailableFeatures, cdn, path=["response"]) + + @parametrize + def test_raw_response_get_available_features(self, client: Gcore) -> None: + response = client.cdn.with_raw_response.get_available_features() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = response.parse() + assert_matches_type(CDNAvailableFeatures, cdn, path=["response"]) + + @parametrize + def test_streaming_response_get_available_features(self, client: Gcore) -> None: + with client.cdn.with_streaming_response.get_available_features() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = response.parse() + assert_matches_type(CDNAvailableFeatures, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_alibaba_regions(self, client: Gcore) -> None: + cdn = client.cdn.list_alibaba_regions() + assert_matches_type(AlibabaRegions, cdn, path=["response"]) + + @parametrize + def test_raw_response_list_alibaba_regions(self, client: Gcore) -> None: + response = client.cdn.with_raw_response.list_alibaba_regions() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = response.parse() + assert_matches_type(AlibabaRegions, cdn, path=["response"]) + + @parametrize + def test_streaming_response_list_alibaba_regions(self, client: Gcore) -> None: + with client.cdn.with_streaming_response.list_alibaba_regions() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = response.parse() + assert_matches_type(AlibabaRegions, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_aws_regions(self, client: Gcore) -> None: + cdn = client.cdn.list_aws_regions() + assert_matches_type(AwsRegions, cdn, path=["response"]) + + @parametrize + def test_raw_response_list_aws_regions(self, client: Gcore) -> None: + response = client.cdn.with_raw_response.list_aws_regions() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = response.parse() + assert_matches_type(AwsRegions, cdn, path=["response"]) + + @parametrize + def test_streaming_response_list_aws_regions(self, client: Gcore) -> None: + with client.cdn.with_streaming_response.list_aws_regions() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = response.parse() + assert_matches_type(AwsRegions, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_purge_statuses(self, client: Gcore) -> None: + cdn = client.cdn.list_purge_statuses() + assert_matches_type(CDNListPurgeStatusesResponse, cdn, path=["response"]) + + @parametrize + def test_method_list_purge_statuses_with_all_params(self, client: Gcore) -> None: + cdn = client.cdn.list_purge_statuses( + cname="cname", + from_created="from_created", + limit=100, + offset=0, + purge_type="purge_type", + status="status", + to_created="to_created", + ) + assert_matches_type(CDNListPurgeStatusesResponse, cdn, path=["response"]) + + @parametrize + def test_raw_response_list_purge_statuses(self, client: Gcore) -> None: + response = client.cdn.with_raw_response.list_purge_statuses() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = response.parse() + assert_matches_type(CDNListPurgeStatusesResponse, cdn, path=["response"]) + + @parametrize + def test_streaming_response_list_purge_statuses(self, client: Gcore) -> None: + with client.cdn.with_streaming_response.list_purge_statuses() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = response.parse() + assert_matches_type(CDNListPurgeStatusesResponse, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update_account(self, client: Gcore) -> None: + cdn = client.cdn.update_account() + assert_matches_type(CDNAccount, cdn, path=["response"]) + + @parametrize + def test_method_update_account_with_all_params(self, client: Gcore) -> None: + cdn = client.cdn.update_account( + utilization_level=1111, + ) + assert_matches_type(CDNAccount, cdn, path=["response"]) + + @parametrize + def test_raw_response_update_account(self, client: Gcore) -> None: + response = client.cdn.with_raw_response.update_account() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = response.parse() + assert_matches_type(CDNAccount, cdn, path=["response"]) + + @parametrize + def test_streaming_response_update_account(self, client: Gcore) -> None: + with client.cdn.with_streaming_response.update_account() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = response.parse() + assert_matches_type(CDNAccount, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncCDN: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_account_limits(self, async_client: AsyncGcore) -> None: + cdn = await async_client.cdn.get_account_limits() + assert_matches_type(CDNAccountLimits, cdn, path=["response"]) + + @parametrize + async def test_raw_response_get_account_limits(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.with_raw_response.get_account_limits() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = await response.parse() + assert_matches_type(CDNAccountLimits, cdn, path=["response"]) + + @parametrize + async def test_streaming_response_get_account_limits(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.with_streaming_response.get_account_limits() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = await response.parse() + assert_matches_type(CDNAccountLimits, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_account_overview(self, async_client: AsyncGcore) -> None: + cdn = await async_client.cdn.get_account_overview() + assert_matches_type(CDNAccount, cdn, path=["response"]) + + @parametrize + async def test_raw_response_get_account_overview(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.with_raw_response.get_account_overview() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = await response.parse() + assert_matches_type(CDNAccount, cdn, path=["response"]) + + @parametrize + async def test_streaming_response_get_account_overview(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.with_streaming_response.get_account_overview() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = await response.parse() + assert_matches_type(CDNAccount, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_available_features(self, async_client: AsyncGcore) -> None: + cdn = await async_client.cdn.get_available_features() + assert_matches_type(CDNAvailableFeatures, cdn, path=["response"]) + + @parametrize + async def test_raw_response_get_available_features(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.with_raw_response.get_available_features() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = await response.parse() + assert_matches_type(CDNAvailableFeatures, cdn, path=["response"]) + + @parametrize + async def test_streaming_response_get_available_features(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.with_streaming_response.get_available_features() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = await response.parse() + assert_matches_type(CDNAvailableFeatures, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_alibaba_regions(self, async_client: AsyncGcore) -> None: + cdn = await async_client.cdn.list_alibaba_regions() + assert_matches_type(AlibabaRegions, cdn, path=["response"]) + + @parametrize + async def test_raw_response_list_alibaba_regions(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.with_raw_response.list_alibaba_regions() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = await response.parse() + assert_matches_type(AlibabaRegions, cdn, path=["response"]) + + @parametrize + async def test_streaming_response_list_alibaba_regions(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.with_streaming_response.list_alibaba_regions() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = await response.parse() + assert_matches_type(AlibabaRegions, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_aws_regions(self, async_client: AsyncGcore) -> None: + cdn = await async_client.cdn.list_aws_regions() + assert_matches_type(AwsRegions, cdn, path=["response"]) + + @parametrize + async def test_raw_response_list_aws_regions(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.with_raw_response.list_aws_regions() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = await response.parse() + assert_matches_type(AwsRegions, cdn, path=["response"]) + + @parametrize + async def test_streaming_response_list_aws_regions(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.with_streaming_response.list_aws_regions() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = await response.parse() + assert_matches_type(AwsRegions, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_purge_statuses(self, async_client: AsyncGcore) -> None: + cdn = await async_client.cdn.list_purge_statuses() + assert_matches_type(CDNListPurgeStatusesResponse, cdn, path=["response"]) + + @parametrize + async def test_method_list_purge_statuses_with_all_params(self, async_client: AsyncGcore) -> None: + cdn = await async_client.cdn.list_purge_statuses( + cname="cname", + from_created="from_created", + limit=100, + offset=0, + purge_type="purge_type", + status="status", + to_created="to_created", + ) + assert_matches_type(CDNListPurgeStatusesResponse, cdn, path=["response"]) + + @parametrize + async def test_raw_response_list_purge_statuses(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.with_raw_response.list_purge_statuses() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = await response.parse() + assert_matches_type(CDNListPurgeStatusesResponse, cdn, path=["response"]) + + @parametrize + async def test_streaming_response_list_purge_statuses(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.with_streaming_response.list_purge_statuses() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = await response.parse() + assert_matches_type(CDNListPurgeStatusesResponse, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update_account(self, async_client: AsyncGcore) -> None: + cdn = await async_client.cdn.update_account() + assert_matches_type(CDNAccount, cdn, path=["response"]) + + @parametrize + async def test_method_update_account_with_all_params(self, async_client: AsyncGcore) -> None: + cdn = await async_client.cdn.update_account( + utilization_level=1111, + ) + assert_matches_type(CDNAccount, cdn, path=["response"]) + + @parametrize + async def test_raw_response_update_account(self, async_client: AsyncGcore) -> None: + response = await async_client.cdn.with_raw_response.update_account() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cdn = await response.parse() + assert_matches_type(CDNAccount, cdn, path=["response"]) + + @parametrize + async def test_streaming_response_update_account(self, async_client: AsyncGcore) -> None: + async with async_client.cdn.with_streaming_response.update_account() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cdn = await response.parse() + assert_matches_type(CDNAccount, cdn, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_dns.py b/tests/api_resources/test_dns.py new file mode 100644 index 00000000..11bfbc7b --- /dev/null +++ b/tests/api_resources/test_dns.py @@ -0,0 +1,140 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.dns import DNSLookupResponse, DNSGetAccountOverviewResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDNS: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_account_overview(self, client: Gcore) -> None: + dns = client.dns.get_account_overview() + assert_matches_type(DNSGetAccountOverviewResponse, dns, path=["response"]) + + @parametrize + def test_raw_response_get_account_overview(self, client: Gcore) -> None: + response = client.dns.with_raw_response.get_account_overview() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dns = response.parse() + assert_matches_type(DNSGetAccountOverviewResponse, dns, path=["response"]) + + @parametrize + def test_streaming_response_get_account_overview(self, client: Gcore) -> None: + with client.dns.with_streaming_response.get_account_overview() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dns = response.parse() + assert_matches_type(DNSGetAccountOverviewResponse, dns, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_lookup(self, client: Gcore) -> None: + dns = client.dns.lookup() + assert_matches_type(DNSLookupResponse, dns, path=["response"]) + + @parametrize + def test_method_lookup_with_all_params(self, client: Gcore) -> None: + dns = client.dns.lookup( + name="name", + request_server="authoritative_dns", + ) + assert_matches_type(DNSLookupResponse, dns, path=["response"]) + + @parametrize + def test_raw_response_lookup(self, client: Gcore) -> None: + response = client.dns.with_raw_response.lookup() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dns = response.parse() + assert_matches_type(DNSLookupResponse, dns, path=["response"]) + + @parametrize + def test_streaming_response_lookup(self, client: Gcore) -> None: + with client.dns.with_streaming_response.lookup() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dns = response.parse() + assert_matches_type(DNSLookupResponse, dns, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncDNS: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_account_overview(self, async_client: AsyncGcore) -> None: + dns = await async_client.dns.get_account_overview() + assert_matches_type(DNSGetAccountOverviewResponse, dns, path=["response"]) + + @parametrize + async def test_raw_response_get_account_overview(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.with_raw_response.get_account_overview() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dns = await response.parse() + assert_matches_type(DNSGetAccountOverviewResponse, dns, path=["response"]) + + @parametrize + async def test_streaming_response_get_account_overview(self, async_client: AsyncGcore) -> None: + async with async_client.dns.with_streaming_response.get_account_overview() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dns = await response.parse() + assert_matches_type(DNSGetAccountOverviewResponse, dns, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_lookup(self, async_client: AsyncGcore) -> None: + dns = await async_client.dns.lookup() + assert_matches_type(DNSLookupResponse, dns, path=["response"]) + + @parametrize + async def test_method_lookup_with_all_params(self, async_client: AsyncGcore) -> None: + dns = await async_client.dns.lookup( + name="name", + request_server="authoritative_dns", + ) + assert_matches_type(DNSLookupResponse, dns, path=["response"]) + + @parametrize + async def test_raw_response_lookup(self, async_client: AsyncGcore) -> None: + response = await async_client.dns.with_raw_response.lookup() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + dns = await response.parse() + assert_matches_type(DNSLookupResponse, dns, path=["response"]) + + @parametrize + async def test_streaming_response_lookup(self, async_client: AsyncGcore) -> None: + async with async_client.dns.with_streaming_response.lookup() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + dns = await response.parse() + assert_matches_type(DNSLookupResponse, dns, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_fastedge.py b/tests/api_resources/test_fastedge.py new file mode 100644 index 00000000..a70099a2 --- /dev/null +++ b/tests/api_resources/test_fastedge.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.fastedge import Client + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFastedge: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_account_overview(self, client: Gcore) -> None: + fastedge = client.fastedge.get_account_overview() + assert_matches_type(Client, fastedge, path=["response"]) + + @parametrize + def test_raw_response_get_account_overview(self, client: Gcore) -> None: + response = client.fastedge.with_raw_response.get_account_overview() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + fastedge = response.parse() + assert_matches_type(Client, fastedge, path=["response"]) + + @parametrize + def test_streaming_response_get_account_overview(self, client: Gcore) -> None: + with client.fastedge.with_streaming_response.get_account_overview() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + fastedge = response.parse() + assert_matches_type(Client, fastedge, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncFastedge: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_account_overview(self, async_client: AsyncGcore) -> None: + fastedge = await async_client.fastedge.get_account_overview() + assert_matches_type(Client, fastedge, path=["response"]) + + @parametrize + async def test_raw_response_get_account_overview(self, async_client: AsyncGcore) -> None: + response = await async_client.fastedge.with_raw_response.get_account_overview() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + fastedge = await response.parse() + assert_matches_type(Client, fastedge, path=["response"]) + + @parametrize + async def test_streaming_response_get_account_overview(self, async_client: AsyncGcore) -> None: + async with async_client.fastedge.with_streaming_response.get_account_overview() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + fastedge = await response.parse() + assert_matches_type(Client, fastedge, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_iam.py b/tests/api_resources/test_iam.py new file mode 100644 index 00000000..58a9d590 --- /dev/null +++ b/tests/api_resources/test_iam.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.iam import AccountOverview + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestIam: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_account_overview(self, client: Gcore) -> None: + iam = client.iam.get_account_overview() + assert_matches_type(AccountOverview, iam, path=["response"]) + + @parametrize + def test_raw_response_get_account_overview(self, client: Gcore) -> None: + response = client.iam.with_raw_response.get_account_overview() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + iam = response.parse() + assert_matches_type(AccountOverview, iam, path=["response"]) + + @parametrize + def test_streaming_response_get_account_overview(self, client: Gcore) -> None: + with client.iam.with_streaming_response.get_account_overview() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + iam = response.parse() + assert_matches_type(AccountOverview, iam, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncIam: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_account_overview(self, async_client: AsyncGcore) -> None: + iam = await async_client.iam.get_account_overview() + assert_matches_type(AccountOverview, iam, path=["response"]) + + @parametrize + async def test_raw_response_get_account_overview(self, async_client: AsyncGcore) -> None: + response = await async_client.iam.with_raw_response.get_account_overview() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + iam = await response.parse() + assert_matches_type(AccountOverview, iam, path=["response"]) + + @parametrize + async def test_streaming_response_get_account_overview(self, async_client: AsyncGcore) -> None: + async with async_client.iam.with_streaming_response.get_account_overview() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + iam = await response.parse() + assert_matches_type(AccountOverview, iam, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_storage.py b/tests/api_resources/test_storage.py new file mode 100644 index 00000000..00988587 --- /dev/null +++ b/tests/api_resources/test_storage.py @@ -0,0 +1,623 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.storage import ( + Storage, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestStorage: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + storage = client.storage.create( + location="s-region-1", + name="my-storage-prod", + type="s3", + ) + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + storage = client.storage.create( + location="s-region-1", + name="my-storage-prod", + type="s3", + generate_sftp_password=True, + sftp_password="sftp_password", + ) + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.storage.with_raw_response.create( + location="s-region-1", + name="my-storage-prod", + type="s3", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = response.parse() + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.storage.with_streaming_response.create( + location="s-region-1", + name="my-storage-prod", + type="s3", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = response.parse() + assert_matches_type(Storage, storage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + storage = client.storage.update( + storage_id=0, + ) + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + storage = client.storage.update( + storage_id=0, + expires="1 years 6 months", + server_alias="my-storage.company.com", + ) + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.storage.with_raw_response.update( + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = response.parse() + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.storage.with_streaming_response.update( + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = response.parse() + assert_matches_type(Storage, storage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + storage = client.storage.list() + assert_matches_type(SyncOffsetPage[Storage], storage, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + storage = client.storage.list( + id="id", + limit=1, + location="location", + name="name", + offset=0, + order_by="order_by", + order_direction="asc", + show_deleted=True, + status="active", + type="s3", + ) + assert_matches_type(SyncOffsetPage[Storage], storage, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.storage.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = response.parse() + assert_matches_type(SyncOffsetPage[Storage], storage, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.storage.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = response.parse() + assert_matches_type(SyncOffsetPage[Storage], storage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + storage = client.storage.delete( + 0, + ) + assert storage is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.storage.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = response.parse() + assert storage is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.storage.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = response.parse() + assert storage is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + storage = client.storage.get( + 0, + ) + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.storage.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = response.parse() + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.storage.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = response.parse() + assert_matches_type(Storage, storage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_link_ssh_key(self, client: Gcore) -> None: + storage = client.storage.link_ssh_key( + key_id=0, + storage_id=0, + ) + assert storage is None + + @parametrize + def test_raw_response_link_ssh_key(self, client: Gcore) -> None: + response = client.storage.with_raw_response.link_ssh_key( + key_id=0, + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = response.parse() + assert storage is None + + @parametrize + def test_streaming_response_link_ssh_key(self, client: Gcore) -> None: + with client.storage.with_streaming_response.link_ssh_key( + key_id=0, + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = response.parse() + assert storage is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_restore(self, client: Gcore) -> None: + storage = client.storage.restore( + storage_id=0, + ) + assert storage is None + + @parametrize + def test_method_restore_with_all_params(self, client: Gcore) -> None: + storage = client.storage.restore( + storage_id=0, + client_id=0, + ) + assert storage is None + + @parametrize + def test_raw_response_restore(self, client: Gcore) -> None: + response = client.storage.with_raw_response.restore( + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = response.parse() + assert storage is None + + @parametrize + def test_streaming_response_restore(self, client: Gcore) -> None: + with client.storage.with_streaming_response.restore( + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = response.parse() + assert storage is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_unlink_ssh_key(self, client: Gcore) -> None: + storage = client.storage.unlink_ssh_key( + key_id=0, + storage_id=0, + ) + assert storage is None + + @parametrize + def test_raw_response_unlink_ssh_key(self, client: Gcore) -> None: + response = client.storage.with_raw_response.unlink_ssh_key( + key_id=0, + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = response.parse() + assert storage is None + + @parametrize + def test_streaming_response_unlink_ssh_key(self, client: Gcore) -> None: + with client.storage.with_streaming_response.unlink_ssh_key( + key_id=0, + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = response.parse() + assert storage is None + + assert cast(Any, response.is_closed) is True + + +class TestAsyncStorage: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + storage = await async_client.storage.create( + location="s-region-1", + name="my-storage-prod", + type="s3", + ) + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + storage = await async_client.storage.create( + location="s-region-1", + name="my-storage-prod", + type="s3", + generate_sftp_password=True, + sftp_password="sftp_password", + ) + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.with_raw_response.create( + location="s-region-1", + name="my-storage-prod", + type="s3", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = await response.parse() + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.storage.with_streaming_response.create( + location="s-region-1", + name="my-storage-prod", + type="s3", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = await response.parse() + assert_matches_type(Storage, storage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + storage = await async_client.storage.update( + storage_id=0, + ) + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + storage = await async_client.storage.update( + storage_id=0, + expires="1 years 6 months", + server_alias="my-storage.company.com", + ) + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.with_raw_response.update( + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = await response.parse() + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.storage.with_streaming_response.update( + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = await response.parse() + assert_matches_type(Storage, storage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + storage = await async_client.storage.list() + assert_matches_type(AsyncOffsetPage[Storage], storage, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + storage = await async_client.storage.list( + id="id", + limit=1, + location="location", + name="name", + offset=0, + order_by="order_by", + order_direction="asc", + show_deleted=True, + status="active", + type="s3", + ) + assert_matches_type(AsyncOffsetPage[Storage], storage, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = await response.parse() + assert_matches_type(AsyncOffsetPage[Storage], storage, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.storage.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = await response.parse() + assert_matches_type(AsyncOffsetPage[Storage], storage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + storage = await async_client.storage.delete( + 0, + ) + assert storage is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = await response.parse() + assert storage is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.storage.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = await response.parse() + assert storage is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + storage = await async_client.storage.get( + 0, + ) + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = await response.parse() + assert_matches_type(Storage, storage, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.storage.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = await response.parse() + assert_matches_type(Storage, storage, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_link_ssh_key(self, async_client: AsyncGcore) -> None: + storage = await async_client.storage.link_ssh_key( + key_id=0, + storage_id=0, + ) + assert storage is None + + @parametrize + async def test_raw_response_link_ssh_key(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.with_raw_response.link_ssh_key( + key_id=0, + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = await response.parse() + assert storage is None + + @parametrize + async def test_streaming_response_link_ssh_key(self, async_client: AsyncGcore) -> None: + async with async_client.storage.with_streaming_response.link_ssh_key( + key_id=0, + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = await response.parse() + assert storage is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_restore(self, async_client: AsyncGcore) -> None: + storage = await async_client.storage.restore( + storage_id=0, + ) + assert storage is None + + @parametrize + async def test_method_restore_with_all_params(self, async_client: AsyncGcore) -> None: + storage = await async_client.storage.restore( + storage_id=0, + client_id=0, + ) + assert storage is None + + @parametrize + async def test_raw_response_restore(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.with_raw_response.restore( + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = await response.parse() + assert storage is None + + @parametrize + async def test_streaming_response_restore(self, async_client: AsyncGcore) -> None: + async with async_client.storage.with_streaming_response.restore( + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = await response.parse() + assert storage is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_unlink_ssh_key(self, async_client: AsyncGcore) -> None: + storage = await async_client.storage.unlink_ssh_key( + key_id=0, + storage_id=0, + ) + assert storage is None + + @parametrize + async def test_raw_response_unlink_ssh_key(self, async_client: AsyncGcore) -> None: + response = await async_client.storage.with_raw_response.unlink_ssh_key( + key_id=0, + storage_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + storage = await response.parse() + assert storage is None + + @parametrize + async def test_streaming_response_unlink_ssh_key(self, async_client: AsyncGcore) -> None: + async with async_client.storage.with_streaming_response.unlink_ssh_key( + key_id=0, + storage_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + storage = await response.parse() + assert storage is None + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_waap.py b/tests/api_resources/test_waap.py new file mode 100644 index 00000000..f006a612 --- /dev/null +++ b/tests/api_resources/test_waap.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.waap import WaapGetAccountOverviewResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestWaap: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_account_overview(self, client: Gcore) -> None: + waap = client.waap.get_account_overview() + assert_matches_type(WaapGetAccountOverviewResponse, waap, path=["response"]) + + @parametrize + def test_raw_response_get_account_overview(self, client: Gcore) -> None: + response = client.waap.with_raw_response.get_account_overview() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + waap = response.parse() + assert_matches_type(WaapGetAccountOverviewResponse, waap, path=["response"]) + + @parametrize + def test_streaming_response_get_account_overview(self, client: Gcore) -> None: + with client.waap.with_streaming_response.get_account_overview() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + waap = response.parse() + assert_matches_type(WaapGetAccountOverviewResponse, waap, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncWaap: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_account_overview(self, async_client: AsyncGcore) -> None: + waap = await async_client.waap.get_account_overview() + assert_matches_type(WaapGetAccountOverviewResponse, waap, path=["response"]) + + @parametrize + async def test_raw_response_get_account_overview(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.with_raw_response.get_account_overview() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + waap = await response.parse() + assert_matches_type(WaapGetAccountOverviewResponse, waap, path=["response"]) + + @parametrize + async def test_streaming_response_get_account_overview(self, async_client: AsyncGcore) -> None: + async with async_client.waap.with_streaming_response.get_account_overview() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + waap = await response.parse() + assert_matches_type(WaapGetAccountOverviewResponse, waap, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/__init__.py b/tests/api_resources/waap/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/waap/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/waap/domains/__init__.py b/tests/api_resources/waap/domains/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/waap/domains/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/waap/domains/test_advanced_rules.py b/tests/api_resources/waap/domains/test_advanced_rules.py new file mode 100644 index 00000000..a049a35b --- /dev/null +++ b/tests/api_resources/waap/domains/test_advanced_rules.py @@ -0,0 +1,577 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.waap.domains import ( + WaapAdvancedRule, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAdvancedRules: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + advanced_rule = client.waap.domains.advanced_rules.create( + domain_id=1, + action={}, + enabled=True, + name="Block foobar bot", + source="request.rate_limit([], '.*events', 5, 200, [], [], '', 'ip') and not ('mb-web-ui' in request.headers['Cookie'] or 'mb-mobile-ios' in request.headers['Cookie'] or 'session-token' in request.headers['Cookie']) and not request.headers['session']", + ) + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + advanced_rule = client.waap.domains.advanced_rules.create( + domain_id=1, + action={ + "allow": {"foo": "bar"}, + "block": { + "action_duration": "12h", + "status_code": 403, + }, + "captcha": {"foo": "bar"}, + "handshake": {"foo": "bar"}, + "monitor": {"foo": "bar"}, + "tag": {"tags": ["string"]}, + }, + enabled=True, + name="Block foobar bot", + source="request.rate_limit([], '.*events', 5, 200, [], [], '', 'ip') and not ('mb-web-ui' in request.headers['Cookie'] or 'mb-mobile-ios' in request.headers['Cookie'] or 'session-token' in request.headers['Cookie']) and not request.headers['session']", + description="description", + phase="access", + ) + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.waap.domains.advanced_rules.with_raw_response.create( + domain_id=1, + action={}, + enabled=True, + name="Block foobar bot", + source="request.rate_limit([], '.*events', 5, 200, [], [], '', 'ip') and not ('mb-web-ui' in request.headers['Cookie'] or 'mb-mobile-ios' in request.headers['Cookie'] or 'session-token' in request.headers['Cookie']) and not request.headers['session']", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = response.parse() + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.waap.domains.advanced_rules.with_streaming_response.create( + domain_id=1, + action={}, + enabled=True, + name="Block foobar bot", + source="request.rate_limit([], '.*events', 5, 200, [], [], '', 'ip') and not ('mb-web-ui' in request.headers['Cookie'] or 'mb-mobile-ios' in request.headers['Cookie'] or 'session-token' in request.headers['Cookie']) and not request.headers['session']", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = response.parse() + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + advanced_rule = client.waap.domains.advanced_rules.update( + rule_id=0, + domain_id=1, + ) + assert advanced_rule is None + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + advanced_rule = client.waap.domains.advanced_rules.update( + rule_id=0, + domain_id=1, + action={ + "allow": {"foo": "bar"}, + "block": { + "action_duration": "12h", + "status_code": 403, + }, + "captcha": {"foo": "bar"}, + "handshake": {"foo": "bar"}, + "monitor": {"foo": "bar"}, + "tag": {"tags": ["string"]}, + }, + description="description", + enabled=True, + name="Block foobar bot", + phase="access", + source="x", + ) + assert advanced_rule is None + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.waap.domains.advanced_rules.with_raw_response.update( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = response.parse() + assert advanced_rule is None + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.waap.domains.advanced_rules.with_streaming_response.update( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = response.parse() + assert advanced_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + advanced_rule = client.waap.domains.advanced_rules.list( + domain_id=1, + ) + assert_matches_type(SyncOffsetPage[WaapAdvancedRule], advanced_rule, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + advanced_rule = client.waap.domains.advanced_rules.list( + domain_id=1, + action="block", + description="This rule blocks all the requests coming form a specific IP address", + enabled=False, + limit=0, + name="Block by specific IP rule", + offset=0, + ordering="-id", + phase="access", + ) + assert_matches_type(SyncOffsetPage[WaapAdvancedRule], advanced_rule, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.waap.domains.advanced_rules.with_raw_response.list( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = response.parse() + assert_matches_type(SyncOffsetPage[WaapAdvancedRule], advanced_rule, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.waap.domains.advanced_rules.with_streaming_response.list( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = response.parse() + assert_matches_type(SyncOffsetPage[WaapAdvancedRule], advanced_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + advanced_rule = client.waap.domains.advanced_rules.delete( + rule_id=0, + domain_id=1, + ) + assert advanced_rule is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.waap.domains.advanced_rules.with_raw_response.delete( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = response.parse() + assert advanced_rule is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.waap.domains.advanced_rules.with_streaming_response.delete( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = response.parse() + assert advanced_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + advanced_rule = client.waap.domains.advanced_rules.get( + rule_id=0, + domain_id=1, + ) + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.waap.domains.advanced_rules.with_raw_response.get( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = response.parse() + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.waap.domains.advanced_rules.with_streaming_response.get( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = response.parse() + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_toggle(self, client: Gcore) -> None: + advanced_rule = client.waap.domains.advanced_rules.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) + assert advanced_rule is None + + @parametrize + def test_raw_response_toggle(self, client: Gcore) -> None: + response = client.waap.domains.advanced_rules.with_raw_response.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = response.parse() + assert advanced_rule is None + + @parametrize + def test_streaming_response_toggle(self, client: Gcore) -> None: + with client.waap.domains.advanced_rules.with_streaming_response.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = response.parse() + assert advanced_rule is None + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAdvancedRules: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + advanced_rule = await async_client.waap.domains.advanced_rules.create( + domain_id=1, + action={}, + enabled=True, + name="Block foobar bot", + source="request.rate_limit([], '.*events', 5, 200, [], [], '', 'ip') and not ('mb-web-ui' in request.headers['Cookie'] or 'mb-mobile-ios' in request.headers['Cookie'] or 'session-token' in request.headers['Cookie']) and not request.headers['session']", + ) + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + advanced_rule = await async_client.waap.domains.advanced_rules.create( + domain_id=1, + action={ + "allow": {"foo": "bar"}, + "block": { + "action_duration": "12h", + "status_code": 403, + }, + "captcha": {"foo": "bar"}, + "handshake": {"foo": "bar"}, + "monitor": {"foo": "bar"}, + "tag": {"tags": ["string"]}, + }, + enabled=True, + name="Block foobar bot", + source="request.rate_limit([], '.*events', 5, 200, [], [], '', 'ip') and not ('mb-web-ui' in request.headers['Cookie'] or 'mb-mobile-ios' in request.headers['Cookie'] or 'session-token' in request.headers['Cookie']) and not request.headers['session']", + description="description", + phase="access", + ) + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.advanced_rules.with_raw_response.create( + domain_id=1, + action={}, + enabled=True, + name="Block foobar bot", + source="request.rate_limit([], '.*events', 5, 200, [], [], '', 'ip') and not ('mb-web-ui' in request.headers['Cookie'] or 'mb-mobile-ios' in request.headers['Cookie'] or 'session-token' in request.headers['Cookie']) and not request.headers['session']", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = await response.parse() + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.advanced_rules.with_streaming_response.create( + domain_id=1, + action={}, + enabled=True, + name="Block foobar bot", + source="request.rate_limit([], '.*events', 5, 200, [], [], '', 'ip') and not ('mb-web-ui' in request.headers['Cookie'] or 'mb-mobile-ios' in request.headers['Cookie'] or 'session-token' in request.headers['Cookie']) and not request.headers['session']", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = await response.parse() + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + advanced_rule = await async_client.waap.domains.advanced_rules.update( + rule_id=0, + domain_id=1, + ) + assert advanced_rule is None + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + advanced_rule = await async_client.waap.domains.advanced_rules.update( + rule_id=0, + domain_id=1, + action={ + "allow": {"foo": "bar"}, + "block": { + "action_duration": "12h", + "status_code": 403, + }, + "captcha": {"foo": "bar"}, + "handshake": {"foo": "bar"}, + "monitor": {"foo": "bar"}, + "tag": {"tags": ["string"]}, + }, + description="description", + enabled=True, + name="Block foobar bot", + phase="access", + source="x", + ) + assert advanced_rule is None + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.advanced_rules.with_raw_response.update( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = await response.parse() + assert advanced_rule is None + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.advanced_rules.with_streaming_response.update( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = await response.parse() + assert advanced_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + advanced_rule = await async_client.waap.domains.advanced_rules.list( + domain_id=1, + ) + assert_matches_type(AsyncOffsetPage[WaapAdvancedRule], advanced_rule, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + advanced_rule = await async_client.waap.domains.advanced_rules.list( + domain_id=1, + action="block", + description="This rule blocks all the requests coming form a specific IP address", + enabled=False, + limit=0, + name="Block by specific IP rule", + offset=0, + ordering="-id", + phase="access", + ) + assert_matches_type(AsyncOffsetPage[WaapAdvancedRule], advanced_rule, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.advanced_rules.with_raw_response.list( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapAdvancedRule], advanced_rule, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.advanced_rules.with_streaming_response.list( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapAdvancedRule], advanced_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + advanced_rule = await async_client.waap.domains.advanced_rules.delete( + rule_id=0, + domain_id=1, + ) + assert advanced_rule is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.advanced_rules.with_raw_response.delete( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = await response.parse() + assert advanced_rule is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.advanced_rules.with_streaming_response.delete( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = await response.parse() + assert advanced_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + advanced_rule = await async_client.waap.domains.advanced_rules.get( + rule_id=0, + domain_id=1, + ) + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.advanced_rules.with_raw_response.get( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = await response.parse() + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.advanced_rules.with_streaming_response.get( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = await response.parse() + assert_matches_type(WaapAdvancedRule, advanced_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_toggle(self, async_client: AsyncGcore) -> None: + advanced_rule = await async_client.waap.domains.advanced_rules.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) + assert advanced_rule is None + + @parametrize + async def test_raw_response_toggle(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.advanced_rules.with_raw_response.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = await response.parse() + assert advanced_rule is None + + @parametrize + async def test_streaming_response_toggle(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.advanced_rules.with_streaming_response.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = await response.parse() + assert advanced_rule is None + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/domains/test_api_discovery.py b/tests/api_resources/waap/domains/test_api_discovery.py new file mode 100644 index 00000000..7fd4e461 --- /dev/null +++ b/tests/api_resources/waap/domains/test_api_discovery.py @@ -0,0 +1,485 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.waap.domains import ( + WaapTaskID, + WaapAPIScanResult, + WaapAPIDiscoverySettings, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAPIDiscovery: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_scan_result(self, client: Gcore) -> None: + api_discovery = client.waap.domains.api_discovery.get_scan_result( + scan_id="scan_id", + domain_id=1, + ) + assert_matches_type(WaapAPIScanResult, api_discovery, path=["response"]) + + @parametrize + def test_raw_response_get_scan_result(self, client: Gcore) -> None: + response = client.waap.domains.api_discovery.with_raw_response.get_scan_result( + scan_id="scan_id", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_discovery = response.parse() + assert_matches_type(WaapAPIScanResult, api_discovery, path=["response"]) + + @parametrize + def test_streaming_response_get_scan_result(self, client: Gcore) -> None: + with client.waap.domains.api_discovery.with_streaming_response.get_scan_result( + scan_id="scan_id", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_discovery = response.parse() + assert_matches_type(WaapAPIScanResult, api_discovery, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_scan_result(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `scan_id` but received ''"): + client.waap.domains.api_discovery.with_raw_response.get_scan_result( + scan_id="", + domain_id=1, + ) + + @parametrize + def test_method_get_settings(self, client: Gcore) -> None: + api_discovery = client.waap.domains.api_discovery.get_settings( + 1, + ) + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + @parametrize + def test_raw_response_get_settings(self, client: Gcore) -> None: + response = client.waap.domains.api_discovery.with_raw_response.get_settings( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_discovery = response.parse() + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + @parametrize + def test_streaming_response_get_settings(self, client: Gcore) -> None: + with client.waap.domains.api_discovery.with_streaming_response.get_settings( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_discovery = response.parse() + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_scan_results(self, client: Gcore) -> None: + api_discovery = client.waap.domains.api_discovery.list_scan_results( + domain_id=1, + ) + assert_matches_type(SyncOffsetPage[WaapAPIScanResult], api_discovery, path=["response"]) + + @parametrize + def test_method_list_scan_results_with_all_params(self, client: Gcore) -> None: + api_discovery = client.waap.domains.api_discovery.list_scan_results( + domain_id=1, + limit=0, + message="message", + offset=0, + ordering="id", + status="SUCCESS", + type="TRAFFIC_SCAN", + ) + assert_matches_type(SyncOffsetPage[WaapAPIScanResult], api_discovery, path=["response"]) + + @parametrize + def test_raw_response_list_scan_results(self, client: Gcore) -> None: + response = client.waap.domains.api_discovery.with_raw_response.list_scan_results( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_discovery = response.parse() + assert_matches_type(SyncOffsetPage[WaapAPIScanResult], api_discovery, path=["response"]) + + @parametrize + def test_streaming_response_list_scan_results(self, client: Gcore) -> None: + with client.waap.domains.api_discovery.with_streaming_response.list_scan_results( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_discovery = response.parse() + assert_matches_type(SyncOffsetPage[WaapAPIScanResult], api_discovery, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_scan_openapi(self, client: Gcore) -> None: + api_discovery = client.waap.domains.api_discovery.scan_openapi( + 1, + ) + assert_matches_type(WaapTaskID, api_discovery, path=["response"]) + + @parametrize + def test_raw_response_scan_openapi(self, client: Gcore) -> None: + response = client.waap.domains.api_discovery.with_raw_response.scan_openapi( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_discovery = response.parse() + assert_matches_type(WaapTaskID, api_discovery, path=["response"]) + + @parametrize + def test_streaming_response_scan_openapi(self, client: Gcore) -> None: + with client.waap.domains.api_discovery.with_streaming_response.scan_openapi( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_discovery = response.parse() + assert_matches_type(WaapTaskID, api_discovery, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update_settings(self, client: Gcore) -> None: + api_discovery = client.waap.domains.api_discovery.update_settings( + domain_id=1, + ) + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + @parametrize + def test_method_update_settings_with_all_params(self, client: Gcore) -> None: + api_discovery = client.waap.domains.api_discovery.update_settings( + domain_id=1, + description_file_location="descriptionFileLocation", + description_file_scan_enabled=True, + description_file_scan_interval_hours=1, + traffic_scan_enabled=True, + traffic_scan_interval_hours=1, + ) + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + @parametrize + def test_raw_response_update_settings(self, client: Gcore) -> None: + response = client.waap.domains.api_discovery.with_raw_response.update_settings( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_discovery = response.parse() + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + @parametrize + def test_streaming_response_update_settings(self, client: Gcore) -> None: + with client.waap.domains.api_discovery.with_streaming_response.update_settings( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_discovery = response.parse() + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_upload_openapi(self, client: Gcore) -> None: + api_discovery = client.waap.domains.api_discovery.upload_openapi( + domain_id=1, + file_data="file_data", + file_name="file_name", + ) + assert_matches_type(WaapTaskID, api_discovery, path=["response"]) + + @parametrize + def test_raw_response_upload_openapi(self, client: Gcore) -> None: + response = client.waap.domains.api_discovery.with_raw_response.upload_openapi( + domain_id=1, + file_data="file_data", + file_name="file_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_discovery = response.parse() + assert_matches_type(WaapTaskID, api_discovery, path=["response"]) + + @parametrize + def test_streaming_response_upload_openapi(self, client: Gcore) -> None: + with client.waap.domains.api_discovery.with_streaming_response.upload_openapi( + domain_id=1, + file_data="file_data", + file_name="file_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_discovery = response.parse() + assert_matches_type(WaapTaskID, api_discovery, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAPIDiscovery: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_scan_result(self, async_client: AsyncGcore) -> None: + api_discovery = await async_client.waap.domains.api_discovery.get_scan_result( + scan_id="scan_id", + domain_id=1, + ) + assert_matches_type(WaapAPIScanResult, api_discovery, path=["response"]) + + @parametrize + async def test_raw_response_get_scan_result(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.api_discovery.with_raw_response.get_scan_result( + scan_id="scan_id", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_discovery = await response.parse() + assert_matches_type(WaapAPIScanResult, api_discovery, path=["response"]) + + @parametrize + async def test_streaming_response_get_scan_result(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.api_discovery.with_streaming_response.get_scan_result( + scan_id="scan_id", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_discovery = await response.parse() + assert_matches_type(WaapAPIScanResult, api_discovery, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_scan_result(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `scan_id` but received ''"): + await async_client.waap.domains.api_discovery.with_raw_response.get_scan_result( + scan_id="", + domain_id=1, + ) + + @parametrize + async def test_method_get_settings(self, async_client: AsyncGcore) -> None: + api_discovery = await async_client.waap.domains.api_discovery.get_settings( + 1, + ) + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + @parametrize + async def test_raw_response_get_settings(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.api_discovery.with_raw_response.get_settings( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_discovery = await response.parse() + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + @parametrize + async def test_streaming_response_get_settings(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.api_discovery.with_streaming_response.get_settings( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_discovery = await response.parse() + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_scan_results(self, async_client: AsyncGcore) -> None: + api_discovery = await async_client.waap.domains.api_discovery.list_scan_results( + domain_id=1, + ) + assert_matches_type(AsyncOffsetPage[WaapAPIScanResult], api_discovery, path=["response"]) + + @parametrize + async def test_method_list_scan_results_with_all_params(self, async_client: AsyncGcore) -> None: + api_discovery = await async_client.waap.domains.api_discovery.list_scan_results( + domain_id=1, + limit=0, + message="message", + offset=0, + ordering="id", + status="SUCCESS", + type="TRAFFIC_SCAN", + ) + assert_matches_type(AsyncOffsetPage[WaapAPIScanResult], api_discovery, path=["response"]) + + @parametrize + async def test_raw_response_list_scan_results(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.api_discovery.with_raw_response.list_scan_results( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_discovery = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapAPIScanResult], api_discovery, path=["response"]) + + @parametrize + async def test_streaming_response_list_scan_results(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.api_discovery.with_streaming_response.list_scan_results( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_discovery = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapAPIScanResult], api_discovery, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_scan_openapi(self, async_client: AsyncGcore) -> None: + api_discovery = await async_client.waap.domains.api_discovery.scan_openapi( + 1, + ) + assert_matches_type(WaapTaskID, api_discovery, path=["response"]) + + @parametrize + async def test_raw_response_scan_openapi(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.api_discovery.with_raw_response.scan_openapi( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_discovery = await response.parse() + assert_matches_type(WaapTaskID, api_discovery, path=["response"]) + + @parametrize + async def test_streaming_response_scan_openapi(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.api_discovery.with_streaming_response.scan_openapi( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_discovery = await response.parse() + assert_matches_type(WaapTaskID, api_discovery, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update_settings(self, async_client: AsyncGcore) -> None: + api_discovery = await async_client.waap.domains.api_discovery.update_settings( + domain_id=1, + ) + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + @parametrize + async def test_method_update_settings_with_all_params(self, async_client: AsyncGcore) -> None: + api_discovery = await async_client.waap.domains.api_discovery.update_settings( + domain_id=1, + description_file_location="descriptionFileLocation", + description_file_scan_enabled=True, + description_file_scan_interval_hours=1, + traffic_scan_enabled=True, + traffic_scan_interval_hours=1, + ) + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + @parametrize + async def test_raw_response_update_settings(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.api_discovery.with_raw_response.update_settings( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_discovery = await response.parse() + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + @parametrize + async def test_streaming_response_update_settings(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.api_discovery.with_streaming_response.update_settings( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_discovery = await response.parse() + assert_matches_type(WaapAPIDiscoverySettings, api_discovery, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_upload_openapi(self, async_client: AsyncGcore) -> None: + api_discovery = await async_client.waap.domains.api_discovery.upload_openapi( + domain_id=1, + file_data="file_data", + file_name="file_name", + ) + assert_matches_type(WaapTaskID, api_discovery, path=["response"]) + + @parametrize + async def test_raw_response_upload_openapi(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.api_discovery.with_raw_response.upload_openapi( + domain_id=1, + file_data="file_data", + file_name="file_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_discovery = await response.parse() + assert_matches_type(WaapTaskID, api_discovery, path=["response"]) + + @parametrize + async def test_streaming_response_upload_openapi(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.api_discovery.with_streaming_response.upload_openapi( + domain_id=1, + file_data="file_data", + file_name="file_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_discovery = await response.parse() + assert_matches_type(WaapTaskID, api_discovery, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/domains/test_api_path_groups.py b/tests/api_resources/waap/domains/test_api_path_groups.py new file mode 100644 index 00000000..d194ade6 --- /dev/null +++ b/tests/api_resources/waap/domains/test_api_path_groups.py @@ -0,0 +1,86 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.waap.domains import APIPathGroupList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAPIPathGroups: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + api_path_group = client.waap.domains.api_path_groups.list( + 1, + ) + assert_matches_type(APIPathGroupList, api_path_group, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.waap.domains.api_path_groups.with_raw_response.list( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_path_group = response.parse() + assert_matches_type(APIPathGroupList, api_path_group, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.waap.domains.api_path_groups.with_streaming_response.list( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_path_group = response.parse() + assert_matches_type(APIPathGroupList, api_path_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAPIPathGroups: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + api_path_group = await async_client.waap.domains.api_path_groups.list( + 1, + ) + assert_matches_type(APIPathGroupList, api_path_group, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.api_path_groups.with_raw_response.list( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_path_group = await response.parse() + assert_matches_type(APIPathGroupList, api_path_group, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.api_path_groups.with_streaming_response.list( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_path_group = await response.parse() + assert_matches_type(APIPathGroupList, api_path_group, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/domains/test_api_paths.py b/tests/api_resources/waap/domains/test_api_paths.py new file mode 100644 index 00000000..18cc8e93 --- /dev/null +++ b/tests/api_resources/waap/domains/test_api_paths.py @@ -0,0 +1,505 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.waap.domains import WaapAPIPath + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAPIPaths: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + api_path = client.waap.domains.api_paths.create( + domain_id=1, + http_scheme="HTTP", + method="GET", + path="/api/v1/paths/{path_id}", + ) + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + api_path = client.waap.domains.api_paths.create( + domain_id=1, + http_scheme="HTTP", + method="GET", + path="/api/v1/paths/{path_id}", + api_groups=["accounts", "internal"], + api_version="v1", + tags=["sensitivedataurl", "highriskurl"], + ) + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.waap.domains.api_paths.with_raw_response.create( + domain_id=1, + http_scheme="HTTP", + method="GET", + path="/api/v1/paths/{path_id}", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_path = response.parse() + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.waap.domains.api_paths.with_streaming_response.create( + domain_id=1, + http_scheme="HTTP", + method="GET", + path="/api/v1/paths/{path_id}", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_path = response.parse() + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + api_path = client.waap.domains.api_paths.update( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + assert api_path is None + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + api_path = client.waap.domains.api_paths.update( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + api_groups=["accounts", "internal"], + path="/api/v1/paths/{path_id}", + status="CONFIRMED_API", + tags=["sensitivedataurl", "highriskurl"], + ) + assert api_path is None + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.waap.domains.api_paths.with_raw_response.update( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_path = response.parse() + assert api_path is None + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.waap.domains.api_paths.with_streaming_response.update( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_path = response.parse() + assert api_path is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"): + client.waap.domains.api_paths.with_raw_response.update( + path_id="", + domain_id=1, + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + api_path = client.waap.domains.api_paths.list( + domain_id=1, + ) + assert_matches_type(SyncOffsetPage[WaapAPIPath], api_path, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + api_path = client.waap.domains.api_paths.list( + domain_id=1, + api_group="api_group", + api_version="api_version", + http_scheme="HTTP", + ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + limit=0, + method="GET", + offset=0, + ordering="id", + path="path", + source="API_DESCRIPTION_FILE", + status=["CONFIRMED_API", "POTENTIAL_API"], + ) + assert_matches_type(SyncOffsetPage[WaapAPIPath], api_path, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.waap.domains.api_paths.with_raw_response.list( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_path = response.parse() + assert_matches_type(SyncOffsetPage[WaapAPIPath], api_path, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.waap.domains.api_paths.with_streaming_response.list( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_path = response.parse() + assert_matches_type(SyncOffsetPage[WaapAPIPath], api_path, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + api_path = client.waap.domains.api_paths.delete( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + assert api_path is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.waap.domains.api_paths.with_raw_response.delete( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_path = response.parse() + assert api_path is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.waap.domains.api_paths.with_streaming_response.delete( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_path = response.parse() + assert api_path is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"): + client.waap.domains.api_paths.with_raw_response.delete( + path_id="", + domain_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + api_path = client.waap.domains.api_paths.get( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.waap.domains.api_paths.with_raw_response.get( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_path = response.parse() + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.waap.domains.api_paths.with_streaming_response.get( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_path = response.parse() + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"): + client.waap.domains.api_paths.with_raw_response.get( + path_id="", + domain_id=1, + ) + + +class TestAsyncAPIPaths: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + api_path = await async_client.waap.domains.api_paths.create( + domain_id=1, + http_scheme="HTTP", + method="GET", + path="/api/v1/paths/{path_id}", + ) + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + api_path = await async_client.waap.domains.api_paths.create( + domain_id=1, + http_scheme="HTTP", + method="GET", + path="/api/v1/paths/{path_id}", + api_groups=["accounts", "internal"], + api_version="v1", + tags=["sensitivedataurl", "highriskurl"], + ) + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.api_paths.with_raw_response.create( + domain_id=1, + http_scheme="HTTP", + method="GET", + path="/api/v1/paths/{path_id}", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_path = await response.parse() + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.api_paths.with_streaming_response.create( + domain_id=1, + http_scheme="HTTP", + method="GET", + path="/api/v1/paths/{path_id}", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_path = await response.parse() + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + api_path = await async_client.waap.domains.api_paths.update( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + assert api_path is None + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + api_path = await async_client.waap.domains.api_paths.update( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + api_groups=["accounts", "internal"], + path="/api/v1/paths/{path_id}", + status="CONFIRMED_API", + tags=["sensitivedataurl", "highriskurl"], + ) + assert api_path is None + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.api_paths.with_raw_response.update( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_path = await response.parse() + assert api_path is None + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.api_paths.with_streaming_response.update( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_path = await response.parse() + assert api_path is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"): + await async_client.waap.domains.api_paths.with_raw_response.update( + path_id="", + domain_id=1, + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + api_path = await async_client.waap.domains.api_paths.list( + domain_id=1, + ) + assert_matches_type(AsyncOffsetPage[WaapAPIPath], api_path, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + api_path = await async_client.waap.domains.api_paths.list( + domain_id=1, + api_group="api_group", + api_version="api_version", + http_scheme="HTTP", + ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + limit=0, + method="GET", + offset=0, + ordering="id", + path="path", + source="API_DESCRIPTION_FILE", + status=["CONFIRMED_API", "POTENTIAL_API"], + ) + assert_matches_type(AsyncOffsetPage[WaapAPIPath], api_path, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.api_paths.with_raw_response.list( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_path = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapAPIPath], api_path, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.api_paths.with_streaming_response.list( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_path = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapAPIPath], api_path, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + api_path = await async_client.waap.domains.api_paths.delete( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + assert api_path is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.api_paths.with_raw_response.delete( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_path = await response.parse() + assert api_path is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.api_paths.with_streaming_response.delete( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_path = await response.parse() + assert api_path is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"): + await async_client.waap.domains.api_paths.with_raw_response.delete( + path_id="", + domain_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + api_path = await async_client.waap.domains.api_paths.get( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.api_paths.with_raw_response.get( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + api_path = await response.parse() + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.api_paths.with_streaming_response.get( + path_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + api_path = await response.parse() + assert_matches_type(WaapAPIPath, api_path, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"): + await async_client.waap.domains.api_paths.with_raw_response.get( + path_id="", + domain_id=1, + ) diff --git a/tests/api_resources/waap/domains/test_custom_rules.py b/tests/api_resources/waap/domains/test_custom_rules.py new file mode 100644 index 00000000..8a2ab6d1 --- /dev/null +++ b/tests/api_resources/waap/domains/test_custom_rules.py @@ -0,0 +1,983 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.waap.domains import ( + WaapCustomRule, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCustomRules: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + custom_rule = client.waap.domains.custom_rules.create( + domain_id=1, + action={}, + conditions=[{}], + enabled=True, + name="Block foobar bot", + ) + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + custom_rule = client.waap.domains.custom_rules.create( + domain_id=1, + action={ + "allow": {"foo": "bar"}, + "block": { + "action_duration": "12h", + "status_code": 403, + }, + "captcha": {"foo": "bar"}, + "handshake": {"foo": "bar"}, + "monitor": {"foo": "bar"}, + "tag": {"tags": ["string"]}, + }, + conditions=[ + { + "content_type": { + "content_type": ["application/xml"], + "negation": True, + }, + "country": { + "country_code": ["Mv"], + "negation": True, + }, + "file_extension": { + "file_extension": ["pdf"], + "negation": True, + }, + "header": { + "header": "Origin", + "value": "value", + "match_type": "Exact", + "negation": True, + }, + "header_exists": { + "header": "Origin", + "negation": True, + }, + "http_method": { + "http_method": "CONNECT", + "negation": True, + }, + "ip": { + "ip_address": "ip_address", + "negation": True, + }, + "ip_range": { + "lower_bound": "lower_bound", + "upper_bound": "upper_bound", + "negation": True, + }, + "organization": { + "organization": "UptimeRobot s.r.o", + "negation": True, + }, + "owner_types": { + "negation": True, + "owner_types": ["COMMERCIAL"], + }, + "request_rate": { + "path_pattern": "/", + "requests": 20, + "time": 1, + "http_methods": ["CONNECT"], + "ips": ["string"], + "user_defined_tag": "SQfNklznVLBBpr", + }, + "response_header": { + "header": "header", + "value": "value", + "match_type": "Exact", + "negation": True, + }, + "response_header_exists": { + "header": "header", + "negation": True, + }, + "session_request_count": { + "request_count": 1, + "negation": True, + }, + "tags": { + "tags": ["string"], + "negation": True, + }, + "url": { + "url": "/wp-admin/", + "match_type": "Exact", + "negation": True, + }, + "user_agent": { + "user_agent": "curl/", + "match_type": "Exact", + "negation": True, + }, + "user_defined_tags": { + "tags": ["SQfNklznVLBBpr"], + "negation": True, + }, + } + ], + enabled=True, + name="Block foobar bot", + description="description", + ) + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.waap.domains.custom_rules.with_raw_response.create( + domain_id=1, + action={}, + conditions=[{}], + enabled=True, + name="Block foobar bot", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = response.parse() + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.waap.domains.custom_rules.with_streaming_response.create( + domain_id=1, + action={}, + conditions=[{}], + enabled=True, + name="Block foobar bot", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = response.parse() + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + custom_rule = client.waap.domains.custom_rules.update( + rule_id=0, + domain_id=1, + ) + assert custom_rule is None + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + custom_rule = client.waap.domains.custom_rules.update( + rule_id=0, + domain_id=1, + action={ + "allow": {"foo": "bar"}, + "block": { + "action_duration": "12h", + "status_code": 403, + }, + "captcha": {"foo": "bar"}, + "handshake": {"foo": "bar"}, + "monitor": {"foo": "bar"}, + "tag": {"tags": ["string"]}, + }, + conditions=[ + { + "content_type": { + "content_type": ["application/xml"], + "negation": True, + }, + "country": { + "country_code": ["Mv"], + "negation": True, + }, + "file_extension": { + "file_extension": ["pdf"], + "negation": True, + }, + "header": { + "header": "Origin", + "value": "value", + "match_type": "Exact", + "negation": True, + }, + "header_exists": { + "header": "Origin", + "negation": True, + }, + "http_method": { + "http_method": "CONNECT", + "negation": True, + }, + "ip": { + "ip_address": "ip_address", + "negation": True, + }, + "ip_range": { + "lower_bound": "lower_bound", + "upper_bound": "upper_bound", + "negation": True, + }, + "organization": { + "organization": "UptimeRobot s.r.o", + "negation": True, + }, + "owner_types": { + "negation": True, + "owner_types": ["COMMERCIAL"], + }, + "request_rate": { + "path_pattern": "/", + "requests": 20, + "time": 1, + "http_methods": ["CONNECT"], + "ips": ["string"], + "user_defined_tag": "SQfNklznVLBBpr", + }, + "response_header": { + "header": "header", + "value": "value", + "match_type": "Exact", + "negation": True, + }, + "response_header_exists": { + "header": "header", + "negation": True, + }, + "session_request_count": { + "request_count": 1, + "negation": True, + }, + "tags": { + "tags": ["string"], + "negation": True, + }, + "url": { + "url": "/wp-admin/", + "match_type": "Exact", + "negation": True, + }, + "user_agent": { + "user_agent": "curl/", + "match_type": "Exact", + "negation": True, + }, + "user_defined_tags": { + "tags": ["SQfNklznVLBBpr"], + "negation": True, + }, + } + ], + description="description", + enabled=True, + name="Block foobar bot", + ) + assert custom_rule is None + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.waap.domains.custom_rules.with_raw_response.update( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = response.parse() + assert custom_rule is None + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.waap.domains.custom_rules.with_streaming_response.update( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = response.parse() + assert custom_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + custom_rule = client.waap.domains.custom_rules.list( + domain_id=1, + ) + assert_matches_type(SyncOffsetPage[WaapCustomRule], custom_rule, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + custom_rule = client.waap.domains.custom_rules.list( + domain_id=1, + action="block", + description="This rule blocks all the requests coming form a specific IP address.", + enabled=False, + limit=0, + name="Block by specific IP rule.", + offset=0, + ordering="-id", + ) + assert_matches_type(SyncOffsetPage[WaapCustomRule], custom_rule, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.waap.domains.custom_rules.with_raw_response.list( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = response.parse() + assert_matches_type(SyncOffsetPage[WaapCustomRule], custom_rule, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.waap.domains.custom_rules.with_streaming_response.list( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = response.parse() + assert_matches_type(SyncOffsetPage[WaapCustomRule], custom_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + custom_rule = client.waap.domains.custom_rules.delete( + rule_id=0, + domain_id=1, + ) + assert custom_rule is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.waap.domains.custom_rules.with_raw_response.delete( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = response.parse() + assert custom_rule is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.waap.domains.custom_rules.with_streaming_response.delete( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = response.parse() + assert custom_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete_multiple(self, client: Gcore) -> None: + custom_rule = client.waap.domains.custom_rules.delete_multiple( + domain_id=1, + rule_ids=[0], + ) + assert custom_rule is None + + @parametrize + def test_raw_response_delete_multiple(self, client: Gcore) -> None: + response = client.waap.domains.custom_rules.with_raw_response.delete_multiple( + domain_id=1, + rule_ids=[0], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = response.parse() + assert custom_rule is None + + @parametrize + def test_streaming_response_delete_multiple(self, client: Gcore) -> None: + with client.waap.domains.custom_rules.with_streaming_response.delete_multiple( + domain_id=1, + rule_ids=[0], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = response.parse() + assert custom_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + custom_rule = client.waap.domains.custom_rules.get( + rule_id=0, + domain_id=1, + ) + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.waap.domains.custom_rules.with_raw_response.get( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = response.parse() + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.waap.domains.custom_rules.with_streaming_response.get( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = response.parse() + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_toggle(self, client: Gcore) -> None: + custom_rule = client.waap.domains.custom_rules.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) + assert custom_rule is None + + @parametrize + def test_raw_response_toggle(self, client: Gcore) -> None: + response = client.waap.domains.custom_rules.with_raw_response.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = response.parse() + assert custom_rule is None + + @parametrize + def test_streaming_response_toggle(self, client: Gcore) -> None: + with client.waap.domains.custom_rules.with_streaming_response.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = response.parse() + assert custom_rule is None + + assert cast(Any, response.is_closed) is True + + +class TestAsyncCustomRules: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + custom_rule = await async_client.waap.domains.custom_rules.create( + domain_id=1, + action={}, + conditions=[{}], + enabled=True, + name="Block foobar bot", + ) + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + custom_rule = await async_client.waap.domains.custom_rules.create( + domain_id=1, + action={ + "allow": {"foo": "bar"}, + "block": { + "action_duration": "12h", + "status_code": 403, + }, + "captcha": {"foo": "bar"}, + "handshake": {"foo": "bar"}, + "monitor": {"foo": "bar"}, + "tag": {"tags": ["string"]}, + }, + conditions=[ + { + "content_type": { + "content_type": ["application/xml"], + "negation": True, + }, + "country": { + "country_code": ["Mv"], + "negation": True, + }, + "file_extension": { + "file_extension": ["pdf"], + "negation": True, + }, + "header": { + "header": "Origin", + "value": "value", + "match_type": "Exact", + "negation": True, + }, + "header_exists": { + "header": "Origin", + "negation": True, + }, + "http_method": { + "http_method": "CONNECT", + "negation": True, + }, + "ip": { + "ip_address": "ip_address", + "negation": True, + }, + "ip_range": { + "lower_bound": "lower_bound", + "upper_bound": "upper_bound", + "negation": True, + }, + "organization": { + "organization": "UptimeRobot s.r.o", + "negation": True, + }, + "owner_types": { + "negation": True, + "owner_types": ["COMMERCIAL"], + }, + "request_rate": { + "path_pattern": "/", + "requests": 20, + "time": 1, + "http_methods": ["CONNECT"], + "ips": ["string"], + "user_defined_tag": "SQfNklznVLBBpr", + }, + "response_header": { + "header": "header", + "value": "value", + "match_type": "Exact", + "negation": True, + }, + "response_header_exists": { + "header": "header", + "negation": True, + }, + "session_request_count": { + "request_count": 1, + "negation": True, + }, + "tags": { + "tags": ["string"], + "negation": True, + }, + "url": { + "url": "/wp-admin/", + "match_type": "Exact", + "negation": True, + }, + "user_agent": { + "user_agent": "curl/", + "match_type": "Exact", + "negation": True, + }, + "user_defined_tags": { + "tags": ["SQfNklznVLBBpr"], + "negation": True, + }, + } + ], + enabled=True, + name="Block foobar bot", + description="description", + ) + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.custom_rules.with_raw_response.create( + domain_id=1, + action={}, + conditions=[{}], + enabled=True, + name="Block foobar bot", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = await response.parse() + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.custom_rules.with_streaming_response.create( + domain_id=1, + action={}, + conditions=[{}], + enabled=True, + name="Block foobar bot", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = await response.parse() + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + custom_rule = await async_client.waap.domains.custom_rules.update( + rule_id=0, + domain_id=1, + ) + assert custom_rule is None + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + custom_rule = await async_client.waap.domains.custom_rules.update( + rule_id=0, + domain_id=1, + action={ + "allow": {"foo": "bar"}, + "block": { + "action_duration": "12h", + "status_code": 403, + }, + "captcha": {"foo": "bar"}, + "handshake": {"foo": "bar"}, + "monitor": {"foo": "bar"}, + "tag": {"tags": ["string"]}, + }, + conditions=[ + { + "content_type": { + "content_type": ["application/xml"], + "negation": True, + }, + "country": { + "country_code": ["Mv"], + "negation": True, + }, + "file_extension": { + "file_extension": ["pdf"], + "negation": True, + }, + "header": { + "header": "Origin", + "value": "value", + "match_type": "Exact", + "negation": True, + }, + "header_exists": { + "header": "Origin", + "negation": True, + }, + "http_method": { + "http_method": "CONNECT", + "negation": True, + }, + "ip": { + "ip_address": "ip_address", + "negation": True, + }, + "ip_range": { + "lower_bound": "lower_bound", + "upper_bound": "upper_bound", + "negation": True, + }, + "organization": { + "organization": "UptimeRobot s.r.o", + "negation": True, + }, + "owner_types": { + "negation": True, + "owner_types": ["COMMERCIAL"], + }, + "request_rate": { + "path_pattern": "/", + "requests": 20, + "time": 1, + "http_methods": ["CONNECT"], + "ips": ["string"], + "user_defined_tag": "SQfNklznVLBBpr", + }, + "response_header": { + "header": "header", + "value": "value", + "match_type": "Exact", + "negation": True, + }, + "response_header_exists": { + "header": "header", + "negation": True, + }, + "session_request_count": { + "request_count": 1, + "negation": True, + }, + "tags": { + "tags": ["string"], + "negation": True, + }, + "url": { + "url": "/wp-admin/", + "match_type": "Exact", + "negation": True, + }, + "user_agent": { + "user_agent": "curl/", + "match_type": "Exact", + "negation": True, + }, + "user_defined_tags": { + "tags": ["SQfNklznVLBBpr"], + "negation": True, + }, + } + ], + description="description", + enabled=True, + name="Block foobar bot", + ) + assert custom_rule is None + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.custom_rules.with_raw_response.update( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = await response.parse() + assert custom_rule is None + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.custom_rules.with_streaming_response.update( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = await response.parse() + assert custom_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + custom_rule = await async_client.waap.domains.custom_rules.list( + domain_id=1, + ) + assert_matches_type(AsyncOffsetPage[WaapCustomRule], custom_rule, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + custom_rule = await async_client.waap.domains.custom_rules.list( + domain_id=1, + action="block", + description="This rule blocks all the requests coming form a specific IP address.", + enabled=False, + limit=0, + name="Block by specific IP rule.", + offset=0, + ordering="-id", + ) + assert_matches_type(AsyncOffsetPage[WaapCustomRule], custom_rule, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.custom_rules.with_raw_response.list( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapCustomRule], custom_rule, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.custom_rules.with_streaming_response.list( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapCustomRule], custom_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + custom_rule = await async_client.waap.domains.custom_rules.delete( + rule_id=0, + domain_id=1, + ) + assert custom_rule is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.custom_rules.with_raw_response.delete( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = await response.parse() + assert custom_rule is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.custom_rules.with_streaming_response.delete( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = await response.parse() + assert custom_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete_multiple(self, async_client: AsyncGcore) -> None: + custom_rule = await async_client.waap.domains.custom_rules.delete_multiple( + domain_id=1, + rule_ids=[0], + ) + assert custom_rule is None + + @parametrize + async def test_raw_response_delete_multiple(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.custom_rules.with_raw_response.delete_multiple( + domain_id=1, + rule_ids=[0], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = await response.parse() + assert custom_rule is None + + @parametrize + async def test_streaming_response_delete_multiple(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.custom_rules.with_streaming_response.delete_multiple( + domain_id=1, + rule_ids=[0], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = await response.parse() + assert custom_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + custom_rule = await async_client.waap.domains.custom_rules.get( + rule_id=0, + domain_id=1, + ) + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.custom_rules.with_raw_response.get( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = await response.parse() + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.custom_rules.with_streaming_response.get( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = await response.parse() + assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_toggle(self, async_client: AsyncGcore) -> None: + custom_rule = await async_client.waap.domains.custom_rules.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) + assert custom_rule is None + + @parametrize + async def test_raw_response_toggle(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.custom_rules.with_raw_response.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_rule = await response.parse() + assert custom_rule is None + + @parametrize + async def test_streaming_response_toggle(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.custom_rules.with_streaming_response.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_rule = await response.parse() + assert custom_rule is None + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/domains/test_firewall_rules.py b/tests/api_resources/waap/domains/test_firewall_rules.py new file mode 100644 index 00000000..10b6fa28 --- /dev/null +++ b/tests/api_resources/waap/domains/test_firewall_rules.py @@ -0,0 +1,671 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.waap.domains import ( + WaapFirewallRule, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFirewallRules: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + firewall_rule = client.waap.domains.firewall_rules.create( + domain_id=1, + action={}, + conditions=[{}], + enabled=True, + name="Block foobar bot", + ) + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + firewall_rule = client.waap.domains.firewall_rules.create( + domain_id=1, + action={ + "allow": {"foo": "bar"}, + "block": { + "action_duration": "12h", + "status_code": 403, + }, + }, + conditions=[ + { + "ip": { + "ip_address": "ip_address", + "negation": True, + }, + "ip_range": { + "lower_bound": "lower_bound", + "upper_bound": "upper_bound", + "negation": True, + }, + } + ], + enabled=True, + name="Block foobar bot", + description="description", + ) + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.waap.domains.firewall_rules.with_raw_response.create( + domain_id=1, + action={}, + conditions=[{}], + enabled=True, + name="Block foobar bot", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = response.parse() + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.waap.domains.firewall_rules.with_streaming_response.create( + domain_id=1, + action={}, + conditions=[{}], + enabled=True, + name="Block foobar bot", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = response.parse() + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + firewall_rule = client.waap.domains.firewall_rules.update( + rule_id=0, + domain_id=1, + ) + assert firewall_rule is None + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + firewall_rule = client.waap.domains.firewall_rules.update( + rule_id=0, + domain_id=1, + action={ + "allow": {"foo": "bar"}, + "block": { + "action_duration": "12h", + "status_code": 403, + }, + }, + conditions=[ + { + "ip": { + "ip_address": "ip_address", + "negation": True, + }, + "ip_range": { + "lower_bound": "lower_bound", + "upper_bound": "upper_bound", + "negation": True, + }, + } + ], + description="description", + enabled=True, + name="Block foobar bot", + ) + assert firewall_rule is None + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.waap.domains.firewall_rules.with_raw_response.update( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = response.parse() + assert firewall_rule is None + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.waap.domains.firewall_rules.with_streaming_response.update( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = response.parse() + assert firewall_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + firewall_rule = client.waap.domains.firewall_rules.list( + domain_id=1, + ) + assert_matches_type(SyncOffsetPage[WaapFirewallRule], firewall_rule, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + firewall_rule = client.waap.domains.firewall_rules.list( + domain_id=1, + action="allow", + description="This rule blocks all the requests coming form a specific IP address.", + enabled=False, + limit=0, + name="Block by specific IP rule.", + offset=0, + ordering="-id", + ) + assert_matches_type(SyncOffsetPage[WaapFirewallRule], firewall_rule, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.waap.domains.firewall_rules.with_raw_response.list( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = response.parse() + assert_matches_type(SyncOffsetPage[WaapFirewallRule], firewall_rule, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.waap.domains.firewall_rules.with_streaming_response.list( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = response.parse() + assert_matches_type(SyncOffsetPage[WaapFirewallRule], firewall_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + firewall_rule = client.waap.domains.firewall_rules.delete( + rule_id=0, + domain_id=1, + ) + assert firewall_rule is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.waap.domains.firewall_rules.with_raw_response.delete( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = response.parse() + assert firewall_rule is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.waap.domains.firewall_rules.with_streaming_response.delete( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = response.parse() + assert firewall_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete_multiple(self, client: Gcore) -> None: + firewall_rule = client.waap.domains.firewall_rules.delete_multiple( + domain_id=1, + rule_ids=[0], + ) + assert firewall_rule is None + + @parametrize + def test_raw_response_delete_multiple(self, client: Gcore) -> None: + response = client.waap.domains.firewall_rules.with_raw_response.delete_multiple( + domain_id=1, + rule_ids=[0], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = response.parse() + assert firewall_rule is None + + @parametrize + def test_streaming_response_delete_multiple(self, client: Gcore) -> None: + with client.waap.domains.firewall_rules.with_streaming_response.delete_multiple( + domain_id=1, + rule_ids=[0], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = response.parse() + assert firewall_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + firewall_rule = client.waap.domains.firewall_rules.get( + rule_id=0, + domain_id=1, + ) + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.waap.domains.firewall_rules.with_raw_response.get( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = response.parse() + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.waap.domains.firewall_rules.with_streaming_response.get( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = response.parse() + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_toggle(self, client: Gcore) -> None: + firewall_rule = client.waap.domains.firewall_rules.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) + assert firewall_rule is None + + @parametrize + def test_raw_response_toggle(self, client: Gcore) -> None: + response = client.waap.domains.firewall_rules.with_raw_response.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = response.parse() + assert firewall_rule is None + + @parametrize + def test_streaming_response_toggle(self, client: Gcore) -> None: + with client.waap.domains.firewall_rules.with_streaming_response.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = response.parse() + assert firewall_rule is None + + assert cast(Any, response.is_closed) is True + + +class TestAsyncFirewallRules: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + firewall_rule = await async_client.waap.domains.firewall_rules.create( + domain_id=1, + action={}, + conditions=[{}], + enabled=True, + name="Block foobar bot", + ) + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + firewall_rule = await async_client.waap.domains.firewall_rules.create( + domain_id=1, + action={ + "allow": {"foo": "bar"}, + "block": { + "action_duration": "12h", + "status_code": 403, + }, + }, + conditions=[ + { + "ip": { + "ip_address": "ip_address", + "negation": True, + }, + "ip_range": { + "lower_bound": "lower_bound", + "upper_bound": "upper_bound", + "negation": True, + }, + } + ], + enabled=True, + name="Block foobar bot", + description="description", + ) + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.firewall_rules.with_raw_response.create( + domain_id=1, + action={}, + conditions=[{}], + enabled=True, + name="Block foobar bot", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = await response.parse() + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.firewall_rules.with_streaming_response.create( + domain_id=1, + action={}, + conditions=[{}], + enabled=True, + name="Block foobar bot", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = await response.parse() + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + firewall_rule = await async_client.waap.domains.firewall_rules.update( + rule_id=0, + domain_id=1, + ) + assert firewall_rule is None + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + firewall_rule = await async_client.waap.domains.firewall_rules.update( + rule_id=0, + domain_id=1, + action={ + "allow": {"foo": "bar"}, + "block": { + "action_duration": "12h", + "status_code": 403, + }, + }, + conditions=[ + { + "ip": { + "ip_address": "ip_address", + "negation": True, + }, + "ip_range": { + "lower_bound": "lower_bound", + "upper_bound": "upper_bound", + "negation": True, + }, + } + ], + description="description", + enabled=True, + name="Block foobar bot", + ) + assert firewall_rule is None + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.firewall_rules.with_raw_response.update( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = await response.parse() + assert firewall_rule is None + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.firewall_rules.with_streaming_response.update( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = await response.parse() + assert firewall_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + firewall_rule = await async_client.waap.domains.firewall_rules.list( + domain_id=1, + ) + assert_matches_type(AsyncOffsetPage[WaapFirewallRule], firewall_rule, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + firewall_rule = await async_client.waap.domains.firewall_rules.list( + domain_id=1, + action="allow", + description="This rule blocks all the requests coming form a specific IP address.", + enabled=False, + limit=0, + name="Block by specific IP rule.", + offset=0, + ordering="-id", + ) + assert_matches_type(AsyncOffsetPage[WaapFirewallRule], firewall_rule, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.firewall_rules.with_raw_response.list( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapFirewallRule], firewall_rule, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.firewall_rules.with_streaming_response.list( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapFirewallRule], firewall_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + firewall_rule = await async_client.waap.domains.firewall_rules.delete( + rule_id=0, + domain_id=1, + ) + assert firewall_rule is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.firewall_rules.with_raw_response.delete( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = await response.parse() + assert firewall_rule is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.firewall_rules.with_streaming_response.delete( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = await response.parse() + assert firewall_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete_multiple(self, async_client: AsyncGcore) -> None: + firewall_rule = await async_client.waap.domains.firewall_rules.delete_multiple( + domain_id=1, + rule_ids=[0], + ) + assert firewall_rule is None + + @parametrize + async def test_raw_response_delete_multiple(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.firewall_rules.with_raw_response.delete_multiple( + domain_id=1, + rule_ids=[0], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = await response.parse() + assert firewall_rule is None + + @parametrize + async def test_streaming_response_delete_multiple(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.firewall_rules.with_streaming_response.delete_multiple( + domain_id=1, + rule_ids=[0], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = await response.parse() + assert firewall_rule is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + firewall_rule = await async_client.waap.domains.firewall_rules.get( + rule_id=0, + domain_id=1, + ) + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.firewall_rules.with_raw_response.get( + rule_id=0, + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = await response.parse() + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.firewall_rules.with_streaming_response.get( + rule_id=0, + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = await response.parse() + assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_toggle(self, async_client: AsyncGcore) -> None: + firewall_rule = await async_client.waap.domains.firewall_rules.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) + assert firewall_rule is None + + @parametrize + async def test_raw_response_toggle(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.firewall_rules.with_raw_response.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + firewall_rule = await response.parse() + assert firewall_rule is None + + @parametrize + async def test_streaming_response_toggle(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.firewall_rules.with_streaming_response.toggle( + action="enable", + domain_id=1, + rule_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + firewall_rule = await response.parse() + assert firewall_rule is None + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/domains/test_insight_silences.py b/tests/api_resources/waap/domains/test_insight_silences.py new file mode 100644 index 00000000..835b21bf --- /dev/null +++ b/tests/api_resources/waap/domains/test_insight_silences.py @@ -0,0 +1,528 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.waap.domains import ( + WaapInsightSilence, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestInsightSilences: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + insight_silence = client.waap.domains.insight_silences.create( + domain_id=1, + author="author", + comment="comment", + insight_type="26f1klzn5713-56bincal4ca-60zz1k91s4", + labels={"foo": "string"}, + ) + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + insight_silence = client.waap.domains.insight_silences.create( + domain_id=1, + author="author", + comment="comment", + insight_type="26f1klzn5713-56bincal4ca-60zz1k91s4", + labels={"foo": "string"}, + expire_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.waap.domains.insight_silences.with_raw_response.create( + domain_id=1, + author="author", + comment="comment", + insight_type="26f1klzn5713-56bincal4ca-60zz1k91s4", + labels={"foo": "string"}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight_silence = response.parse() + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.waap.domains.insight_silences.with_streaming_response.create( + domain_id=1, + author="author", + comment="comment", + insight_type="26f1klzn5713-56bincal4ca-60zz1k91s4", + labels={"foo": "string"}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight_silence = response.parse() + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + insight_silence = client.waap.domains.insight_silences.update( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + author="author", + comment="comment", + expire_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + insight_silence = client.waap.domains.insight_silences.update( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + author="author", + comment="comment", + expire_at=parse_datetime("2019-12-27T18:11:19.117Z"), + labels={"foo": "string"}, + ) + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.waap.domains.insight_silences.with_raw_response.update( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + author="author", + comment="comment", + expire_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight_silence = response.parse() + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.waap.domains.insight_silences.with_streaming_response.update( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + author="author", + comment="comment", + expire_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight_silence = response.parse() + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `silence_id` but received ''"): + client.waap.domains.insight_silences.with_raw_response.update( + silence_id="", + domain_id=1, + author="author", + comment="comment", + expire_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + insight_silence = client.waap.domains.insight_silences.list( + domain_id=1, + ) + assert_matches_type(SyncOffsetPage[WaapInsightSilence], insight_silence, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + insight_silence = client.waap.domains.insight_silences.list( + domain_id=1, + id=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + author="author", + comment="comment", + insight_type=["string", "string"], + limit=0, + offset=0, + ordering="id", + ) + assert_matches_type(SyncOffsetPage[WaapInsightSilence], insight_silence, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.waap.domains.insight_silences.with_raw_response.list( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight_silence = response.parse() + assert_matches_type(SyncOffsetPage[WaapInsightSilence], insight_silence, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.waap.domains.insight_silences.with_streaming_response.list( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight_silence = response.parse() + assert_matches_type(SyncOffsetPage[WaapInsightSilence], insight_silence, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + insight_silence = client.waap.domains.insight_silences.delete( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + assert insight_silence is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.waap.domains.insight_silences.with_raw_response.delete( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight_silence = response.parse() + assert insight_silence is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.waap.domains.insight_silences.with_streaming_response.delete( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight_silence = response.parse() + assert insight_silence is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `silence_id` but received ''"): + client.waap.domains.insight_silences.with_raw_response.delete( + silence_id="", + domain_id=1, + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + insight_silence = client.waap.domains.insight_silences.get( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.waap.domains.insight_silences.with_raw_response.get( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight_silence = response.parse() + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.waap.domains.insight_silences.with_streaming_response.get( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight_silence = response.parse() + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `silence_id` but received ''"): + client.waap.domains.insight_silences.with_raw_response.get( + silence_id="", + domain_id=1, + ) + + +class TestAsyncInsightSilences: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + insight_silence = await async_client.waap.domains.insight_silences.create( + domain_id=1, + author="author", + comment="comment", + insight_type="26f1klzn5713-56bincal4ca-60zz1k91s4", + labels={"foo": "string"}, + ) + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + insight_silence = await async_client.waap.domains.insight_silences.create( + domain_id=1, + author="author", + comment="comment", + insight_type="26f1klzn5713-56bincal4ca-60zz1k91s4", + labels={"foo": "string"}, + expire_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.insight_silences.with_raw_response.create( + domain_id=1, + author="author", + comment="comment", + insight_type="26f1klzn5713-56bincal4ca-60zz1k91s4", + labels={"foo": "string"}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight_silence = await response.parse() + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.insight_silences.with_streaming_response.create( + domain_id=1, + author="author", + comment="comment", + insight_type="26f1klzn5713-56bincal4ca-60zz1k91s4", + labels={"foo": "string"}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight_silence = await response.parse() + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + insight_silence = await async_client.waap.domains.insight_silences.update( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + author="author", + comment="comment", + expire_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + insight_silence = await async_client.waap.domains.insight_silences.update( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + author="author", + comment="comment", + expire_at=parse_datetime("2019-12-27T18:11:19.117Z"), + labels={"foo": "string"}, + ) + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.insight_silences.with_raw_response.update( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + author="author", + comment="comment", + expire_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight_silence = await response.parse() + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.insight_silences.with_streaming_response.update( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + author="author", + comment="comment", + expire_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight_silence = await response.parse() + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `silence_id` but received ''"): + await async_client.waap.domains.insight_silences.with_raw_response.update( + silence_id="", + domain_id=1, + author="author", + comment="comment", + expire_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + insight_silence = await async_client.waap.domains.insight_silences.list( + domain_id=1, + ) + assert_matches_type(AsyncOffsetPage[WaapInsightSilence], insight_silence, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + insight_silence = await async_client.waap.domains.insight_silences.list( + domain_id=1, + id=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + author="author", + comment="comment", + insight_type=["string", "string"], + limit=0, + offset=0, + ordering="id", + ) + assert_matches_type(AsyncOffsetPage[WaapInsightSilence], insight_silence, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.insight_silences.with_raw_response.list( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight_silence = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapInsightSilence], insight_silence, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.insight_silences.with_streaming_response.list( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight_silence = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapInsightSilence], insight_silence, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + insight_silence = await async_client.waap.domains.insight_silences.delete( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + assert insight_silence is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.insight_silences.with_raw_response.delete( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight_silence = await response.parse() + assert insight_silence is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.insight_silences.with_streaming_response.delete( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight_silence = await response.parse() + assert insight_silence is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `silence_id` but received ''"): + await async_client.waap.domains.insight_silences.with_raw_response.delete( + silence_id="", + domain_id=1, + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + insight_silence = await async_client.waap.domains.insight_silences.get( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.insight_silences.with_raw_response.get( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight_silence = await response.parse() + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.insight_silences.with_streaming_response.get( + silence_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight_silence = await response.parse() + assert_matches_type(WaapInsightSilence, insight_silence, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `silence_id` but received ''"): + await async_client.waap.domains.insight_silences.with_raw_response.get( + silence_id="", + domain_id=1, + ) diff --git a/tests/api_resources/waap/domains/test_insights.py b/tests/api_resources/waap/domains/test_insights.py new file mode 100644 index 00000000..2e2f83b1 --- /dev/null +++ b/tests/api_resources/waap/domains/test_insights.py @@ -0,0 +1,291 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.waap.domains import WaapInsight + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestInsights: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + insight = client.waap.domains.insights.list( + domain_id=1, + ) + assert_matches_type(SyncOffsetPage[WaapInsight], insight, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + insight = client.waap.domains.insights.list( + domain_id=1, + id=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + description="description", + insight_type=["string", "string"], + limit=0, + offset=0, + ordering="id", + status=["OPEN", "ACKED"], + ) + assert_matches_type(SyncOffsetPage[WaapInsight], insight, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.waap.domains.insights.with_raw_response.list( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight = response.parse() + assert_matches_type(SyncOffsetPage[WaapInsight], insight, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.waap.domains.insights.with_streaming_response.list( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight = response.parse() + assert_matches_type(SyncOffsetPage[WaapInsight], insight, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + insight = client.waap.domains.insights.get( + insight_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + assert_matches_type(WaapInsight, insight, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.waap.domains.insights.with_raw_response.get( + insight_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight = response.parse() + assert_matches_type(WaapInsight, insight, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.waap.domains.insights.with_streaming_response.get( + insight_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight = response.parse() + assert_matches_type(WaapInsight, insight, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `insight_id` but received ''"): + client.waap.domains.insights.with_raw_response.get( + insight_id="", + domain_id=1, + ) + + @parametrize + def test_method_replace(self, client: Gcore) -> None: + insight = client.waap.domains.insights.replace( + insight_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + status="OPEN", + ) + assert_matches_type(WaapInsight, insight, path=["response"]) + + @parametrize + def test_raw_response_replace(self, client: Gcore) -> None: + response = client.waap.domains.insights.with_raw_response.replace( + insight_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + status="OPEN", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight = response.parse() + assert_matches_type(WaapInsight, insight, path=["response"]) + + @parametrize + def test_streaming_response_replace(self, client: Gcore) -> None: + with client.waap.domains.insights.with_streaming_response.replace( + insight_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + status="OPEN", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight = response.parse() + assert_matches_type(WaapInsight, insight, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_replace(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `insight_id` but received ''"): + client.waap.domains.insights.with_raw_response.replace( + insight_id="", + domain_id=1, + status="OPEN", + ) + + +class TestAsyncInsights: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + insight = await async_client.waap.domains.insights.list( + domain_id=1, + ) + assert_matches_type(AsyncOffsetPage[WaapInsight], insight, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + insight = await async_client.waap.domains.insights.list( + domain_id=1, + id=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + description="description", + insight_type=["string", "string"], + limit=0, + offset=0, + ordering="id", + status=["OPEN", "ACKED"], + ) + assert_matches_type(AsyncOffsetPage[WaapInsight], insight, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.insights.with_raw_response.list( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapInsight], insight, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.insights.with_streaming_response.list( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapInsight], insight, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + insight = await async_client.waap.domains.insights.get( + insight_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + assert_matches_type(WaapInsight, insight, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.insights.with_raw_response.get( + insight_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight = await response.parse() + assert_matches_type(WaapInsight, insight, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.insights.with_streaming_response.get( + insight_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight = await response.parse() + assert_matches_type(WaapInsight, insight, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `insight_id` but received ''"): + await async_client.waap.domains.insights.with_raw_response.get( + insight_id="", + domain_id=1, + ) + + @parametrize + async def test_method_replace(self, async_client: AsyncGcore) -> None: + insight = await async_client.waap.domains.insights.replace( + insight_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + status="OPEN", + ) + assert_matches_type(WaapInsight, insight, path=["response"]) + + @parametrize + async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.insights.with_raw_response.replace( + insight_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + status="OPEN", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight = await response.parse() + assert_matches_type(WaapInsight, insight, path=["response"]) + + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.insights.with_streaming_response.replace( + insight_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + domain_id=1, + status="OPEN", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight = await response.parse() + assert_matches_type(WaapInsight, insight, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_replace(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `insight_id` but received ''"): + await async_client.waap.domains.insights.with_raw_response.replace( + insight_id="", + domain_id=1, + status="OPEN", + ) diff --git a/tests/api_resources/waap/domains/test_settings.py b/tests/api_resources/waap/domains/test_settings.py new file mode 100644 index 00000000..38e68c8e --- /dev/null +++ b/tests/api_resources/waap/domains/test_settings.py @@ -0,0 +1,178 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.waap import WaapDomainSettingsModel + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSettings: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_update(self, client: Gcore) -> None: + setting = client.waap.domains.settings.update( + domain_id=1, + ) + assert setting is None + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + setting = client.waap.domains.settings.update( + domain_id=1, + api={ + "api_urls": ["api/v1/.*", "v2/.*"], + "is_api": True, + }, + ddos={ + "burst_threshold": 30, + "global_threshold": 250, + }, + ) + assert setting is None + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.waap.domains.settings.with_raw_response.update( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + setting = response.parse() + assert setting is None + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.waap.domains.settings.with_streaming_response.update( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + setting = response.parse() + assert setting is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + setting = client.waap.domains.settings.get( + 1, + ) + assert_matches_type(WaapDomainSettingsModel, setting, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.waap.domains.settings.with_raw_response.get( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + setting = response.parse() + assert_matches_type(WaapDomainSettingsModel, setting, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.waap.domains.settings.with_streaming_response.get( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + setting = response.parse() + assert_matches_type(WaapDomainSettingsModel, setting, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncSettings: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + setting = await async_client.waap.domains.settings.update( + domain_id=1, + ) + assert setting is None + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + setting = await async_client.waap.domains.settings.update( + domain_id=1, + api={ + "api_urls": ["api/v1/.*", "v2/.*"], + "is_api": True, + }, + ddos={ + "burst_threshold": 30, + "global_threshold": 250, + }, + ) + assert setting is None + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.settings.with_raw_response.update( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + setting = await response.parse() + assert setting is None + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.settings.with_streaming_response.update( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + setting = await response.parse() + assert setting is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + setting = await async_client.waap.domains.settings.get( + 1, + ) + assert_matches_type(WaapDomainSettingsModel, setting, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.settings.with_raw_response.get( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + setting = await response.parse() + assert_matches_type(WaapDomainSettingsModel, setting, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.settings.with_streaming_response.get( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + setting = await response.parse() + assert_matches_type(WaapDomainSettingsModel, setting, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/domains/test_statistics.py b/tests/api_resources/waap/domains/test_statistics.py new file mode 100644 index 00000000..da599e1c --- /dev/null +++ b/tests/api_resources/waap/domains/test_statistics.py @@ -0,0 +1,621 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.waap.domains import ( + WaapDDOSInfo, + WaapDDOSAttack, + WaapRequestDetails, + WaapRequestSummary, + WaapEventStatistics, + StatisticGetTrafficSeriesResponse, +) + +# pyright: reportDeprecated=false + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestStatistics: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_ddos_attacks(self, client: Gcore) -> None: + statistic = client.waap.domains.statistics.get_ddos_attacks( + domain_id=1, + ) + assert_matches_type(SyncOffsetPage[WaapDDOSAttack], statistic, path=["response"]) + + @parametrize + def test_method_get_ddos_attacks_with_all_params(self, client: Gcore) -> None: + statistic = client.waap.domains.statistics.get_ddos_attacks( + domain_id=1, + end_time=parse_datetime("2024-04-27T13:00:00Z"), + limit=0, + offset=0, + ordering="start_time", + start_time=parse_datetime("2024-04-26T13:32:49Z"), + ) + assert_matches_type(SyncOffsetPage[WaapDDOSAttack], statistic, path=["response"]) + + @parametrize + def test_raw_response_get_ddos_attacks(self, client: Gcore) -> None: + response = client.waap.domains.statistics.with_raw_response.get_ddos_attacks( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(SyncOffsetPage[WaapDDOSAttack], statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_ddos_attacks(self, client: Gcore) -> None: + with client.waap.domains.statistics.with_streaming_response.get_ddos_attacks( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(SyncOffsetPage[WaapDDOSAttack], statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_ddos_info(self, client: Gcore) -> None: + statistic = client.waap.domains.statistics.get_ddos_info( + domain_id=1, + group_by="URL", + start="2024-04-13T00:00:00+01:00", + ) + assert_matches_type(SyncOffsetPage[WaapDDOSInfo], statistic, path=["response"]) + + @parametrize + def test_method_get_ddos_info_with_all_params(self, client: Gcore) -> None: + statistic = client.waap.domains.statistics.get_ddos_info( + domain_id=1, + group_by="URL", + start="2024-04-13T00:00:00+01:00", + end="2024-04-14T12:00:00Z", + limit=0, + offset=0, + ) + assert_matches_type(SyncOffsetPage[WaapDDOSInfo], statistic, path=["response"]) + + @parametrize + def test_raw_response_get_ddos_info(self, client: Gcore) -> None: + response = client.waap.domains.statistics.with_raw_response.get_ddos_info( + domain_id=1, + group_by="URL", + start="2024-04-13T00:00:00+01:00", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(SyncOffsetPage[WaapDDOSInfo], statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_ddos_info(self, client: Gcore) -> None: + with client.waap.domains.statistics.with_streaming_response.get_ddos_info( + domain_id=1, + group_by="URL", + start="2024-04-13T00:00:00+01:00", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(SyncOffsetPage[WaapDDOSInfo], statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_events_aggregated(self, client: Gcore) -> None: + statistic = client.waap.domains.statistics.get_events_aggregated( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + ) + assert_matches_type(WaapEventStatistics, statistic, path=["response"]) + + @parametrize + def test_method_get_events_aggregated_with_all_params(self, client: Gcore) -> None: + statistic = client.waap.domains.statistics.get_events_aggregated( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + action=["allow", "block"], + end="2024-04-14T12:00:00Z", + ip=["string", "string"], + reference_id=["string", "string"], + result=["passed", "blocked"], + ) + assert_matches_type(WaapEventStatistics, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_events_aggregated(self, client: Gcore) -> None: + response = client.waap.domains.statistics.with_raw_response.get_events_aggregated( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(WaapEventStatistics, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_events_aggregated(self, client: Gcore) -> None: + with client.waap.domains.statistics.with_streaming_response.get_events_aggregated( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(WaapEventStatistics, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_request_details(self, client: Gcore) -> None: + statistic = client.waap.domains.statistics.get_request_details( + request_id="request_id", + domain_id=1, + ) + assert_matches_type(WaapRequestDetails, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_request_details(self, client: Gcore) -> None: + response = client.waap.domains.statistics.with_raw_response.get_request_details( + request_id="request_id", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(WaapRequestDetails, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_request_details(self, client: Gcore) -> None: + with client.waap.domains.statistics.with_streaming_response.get_request_details( + request_id="request_id", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(WaapRequestDetails, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_request_details(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `request_id` but received ''"): + client.waap.domains.statistics.with_raw_response.get_request_details( + request_id="", + domain_id=1, + ) + + @parametrize + def test_method_get_requests_series(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + statistic = client.waap.domains.statistics.get_requests_series( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + ) + + assert_matches_type(SyncOffsetPage[WaapRequestSummary], statistic, path=["response"]) + + @parametrize + def test_method_get_requests_series_with_all_params(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + statistic = client.waap.domains.statistics.get_requests_series( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + actions=["allow"], + countries=["Mv"], + end="2024-04-14T12:00:00Z", + ip=".:", + limit=0, + offset=0, + ordering="ordering", + reference_id="ad07c06f19054e484974fa22e9fb6bb1", + security_rule_name="security_rule_name", + status_code=100, + traffic_types=["policy_allowed"], + ) + + assert_matches_type(SyncOffsetPage[WaapRequestSummary], statistic, path=["response"]) + + @parametrize + def test_raw_response_get_requests_series(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + response = client.waap.domains.statistics.with_raw_response.get_requests_series( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(SyncOffsetPage[WaapRequestSummary], statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_requests_series(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with client.waap.domains.statistics.with_streaming_response.get_requests_series( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(SyncOffsetPage[WaapRequestSummary], statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_traffic_series(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + statistic = client.waap.domains.statistics.get_traffic_series( + domain_id=1, + resolution="daily", + start="2024-04-13T00:00:00+01:00", + ) + + assert_matches_type(StatisticGetTrafficSeriesResponse, statistic, path=["response"]) + + @parametrize + def test_method_get_traffic_series_with_all_params(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + statistic = client.waap.domains.statistics.get_traffic_series( + domain_id=1, + resolution="daily", + start="2024-04-13T00:00:00+01:00", + end="2024-04-14T12:00:00Z", + ) + + assert_matches_type(StatisticGetTrafficSeriesResponse, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_traffic_series(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + response = client.waap.domains.statistics.with_raw_response.get_traffic_series( + domain_id=1, + resolution="daily", + start="2024-04-13T00:00:00+01:00", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(StatisticGetTrafficSeriesResponse, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_traffic_series(self, client: Gcore) -> None: + with pytest.warns(DeprecationWarning): + with client.waap.domains.statistics.with_streaming_response.get_traffic_series( + domain_id=1, + resolution="daily", + start="2024-04-13T00:00:00+01:00", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(StatisticGetTrafficSeriesResponse, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncStatistics: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_ddos_attacks(self, async_client: AsyncGcore) -> None: + statistic = await async_client.waap.domains.statistics.get_ddos_attacks( + domain_id=1, + ) + assert_matches_type(AsyncOffsetPage[WaapDDOSAttack], statistic, path=["response"]) + + @parametrize + async def test_method_get_ddos_attacks_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.waap.domains.statistics.get_ddos_attacks( + domain_id=1, + end_time=parse_datetime("2024-04-27T13:00:00Z"), + limit=0, + offset=0, + ordering="start_time", + start_time=parse_datetime("2024-04-26T13:32:49Z"), + ) + assert_matches_type(AsyncOffsetPage[WaapDDOSAttack], statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_ddos_attacks(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.statistics.with_raw_response.get_ddos_attacks( + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapDDOSAttack], statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_ddos_attacks(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.statistics.with_streaming_response.get_ddos_attacks( + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapDDOSAttack], statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_ddos_info(self, async_client: AsyncGcore) -> None: + statistic = await async_client.waap.domains.statistics.get_ddos_info( + domain_id=1, + group_by="URL", + start="2024-04-13T00:00:00+01:00", + ) + assert_matches_type(AsyncOffsetPage[WaapDDOSInfo], statistic, path=["response"]) + + @parametrize + async def test_method_get_ddos_info_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.waap.domains.statistics.get_ddos_info( + domain_id=1, + group_by="URL", + start="2024-04-13T00:00:00+01:00", + end="2024-04-14T12:00:00Z", + limit=0, + offset=0, + ) + assert_matches_type(AsyncOffsetPage[WaapDDOSInfo], statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_ddos_info(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.statistics.with_raw_response.get_ddos_info( + domain_id=1, + group_by="URL", + start="2024-04-13T00:00:00+01:00", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapDDOSInfo], statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_ddos_info(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.statistics.with_streaming_response.get_ddos_info( + domain_id=1, + group_by="URL", + start="2024-04-13T00:00:00+01:00", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapDDOSInfo], statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_events_aggregated(self, async_client: AsyncGcore) -> None: + statistic = await async_client.waap.domains.statistics.get_events_aggregated( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + ) + assert_matches_type(WaapEventStatistics, statistic, path=["response"]) + + @parametrize + async def test_method_get_events_aggregated_with_all_params(self, async_client: AsyncGcore) -> None: + statistic = await async_client.waap.domains.statistics.get_events_aggregated( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + action=["allow", "block"], + end="2024-04-14T12:00:00Z", + ip=["string", "string"], + reference_id=["string", "string"], + result=["passed", "blocked"], + ) + assert_matches_type(WaapEventStatistics, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_events_aggregated(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.statistics.with_raw_response.get_events_aggregated( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(WaapEventStatistics, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_events_aggregated(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.statistics.with_streaming_response.get_events_aggregated( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(WaapEventStatistics, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_request_details(self, async_client: AsyncGcore) -> None: + statistic = await async_client.waap.domains.statistics.get_request_details( + request_id="request_id", + domain_id=1, + ) + assert_matches_type(WaapRequestDetails, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_request_details(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.statistics.with_raw_response.get_request_details( + request_id="request_id", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(WaapRequestDetails, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_request_details(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.statistics.with_streaming_response.get_request_details( + request_id="request_id", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(WaapRequestDetails, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_request_details(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `request_id` but received ''"): + await async_client.waap.domains.statistics.with_raw_response.get_request_details( + request_id="", + domain_id=1, + ) + + @parametrize + async def test_method_get_requests_series(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + statistic = await async_client.waap.domains.statistics.get_requests_series( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + ) + + assert_matches_type(AsyncOffsetPage[WaapRequestSummary], statistic, path=["response"]) + + @parametrize + async def test_method_get_requests_series_with_all_params(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + statistic = await async_client.waap.domains.statistics.get_requests_series( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + actions=["allow"], + countries=["Mv"], + end="2024-04-14T12:00:00Z", + ip=".:", + limit=0, + offset=0, + ordering="ordering", + reference_id="ad07c06f19054e484974fa22e9fb6bb1", + security_rule_name="security_rule_name", + status_code=100, + traffic_types=["policy_allowed"], + ) + + assert_matches_type(AsyncOffsetPage[WaapRequestSummary], statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_requests_series(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + response = await async_client.waap.domains.statistics.with_raw_response.get_requests_series( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapRequestSummary], statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_requests_series(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + async with async_client.waap.domains.statistics.with_streaming_response.get_requests_series( + domain_id=1, + start="2024-04-13T00:00:00+01:00", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapRequestSummary], statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_traffic_series(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + statistic = await async_client.waap.domains.statistics.get_traffic_series( + domain_id=1, + resolution="daily", + start="2024-04-13T00:00:00+01:00", + ) + + assert_matches_type(StatisticGetTrafficSeriesResponse, statistic, path=["response"]) + + @parametrize + async def test_method_get_traffic_series_with_all_params(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + statistic = await async_client.waap.domains.statistics.get_traffic_series( + domain_id=1, + resolution="daily", + start="2024-04-13T00:00:00+01:00", + end="2024-04-14T12:00:00Z", + ) + + assert_matches_type(StatisticGetTrafficSeriesResponse, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_traffic_series(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + response = await async_client.waap.domains.statistics.with_raw_response.get_traffic_series( + domain_id=1, + resolution="daily", + start="2024-04-13T00:00:00+01:00", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(StatisticGetTrafficSeriesResponse, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_traffic_series(self, async_client: AsyncGcore) -> None: + with pytest.warns(DeprecationWarning): + async with async_client.waap.domains.statistics.with_streaming_response.get_traffic_series( + domain_id=1, + resolution="daily", + start="2024-04-13T00:00:00+01:00", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(StatisticGetTrafficSeriesResponse, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/ip_info/__init__.py b/tests/api_resources/waap/ip_info/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/waap/ip_info/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/waap/ip_info/test_metrics.py b/tests/api_resources/waap/ip_info/test_metrics.py new file mode 100644 index 00000000..70fb8543 --- /dev/null +++ b/tests/api_resources/waap/ip_info/test_metrics.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.waap.ip_info import WaapIPInfoCounts + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMetrics: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + metric = client.waap.ip_info.metrics.list( + ip="192.168.1.1", + ) + assert_matches_type(WaapIPInfoCounts, metric, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + metric = client.waap.ip_info.metrics.list( + ip="192.168.1.1", + domain_id=1, + ) + assert_matches_type(WaapIPInfoCounts, metric, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.waap.ip_info.metrics.with_raw_response.list( + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + metric = response.parse() + assert_matches_type(WaapIPInfoCounts, metric, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.waap.ip_info.metrics.with_streaming_response.list( + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + metric = response.parse() + assert_matches_type(WaapIPInfoCounts, metric, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncMetrics: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + metric = await async_client.waap.ip_info.metrics.list( + ip="192.168.1.1", + ) + assert_matches_type(WaapIPInfoCounts, metric, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + metric = await async_client.waap.ip_info.metrics.list( + ip="192.168.1.1", + domain_id=1, + ) + assert_matches_type(WaapIPInfoCounts, metric, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.ip_info.metrics.with_raw_response.list( + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + metric = await response.parse() + assert_matches_type(WaapIPInfoCounts, metric, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.waap.ip_info.metrics.with_streaming_response.list( + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + metric = await response.parse() + assert_matches_type(WaapIPInfoCounts, metric, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/test_advanced_rules.py b/tests/api_resources/waap/test_advanced_rules.py new file mode 100644 index 00000000..d61c91af --- /dev/null +++ b/tests/api_resources/waap/test_advanced_rules.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.waap import WaapAdvancedRuleDescriptorList + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAdvancedRules: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + advanced_rule = client.waap.advanced_rules.list() + assert_matches_type(WaapAdvancedRuleDescriptorList, advanced_rule, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.waap.advanced_rules.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = response.parse() + assert_matches_type(WaapAdvancedRuleDescriptorList, advanced_rule, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.waap.advanced_rules.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = response.parse() + assert_matches_type(WaapAdvancedRuleDescriptorList, advanced_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAdvancedRules: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + advanced_rule = await async_client.waap.advanced_rules.list() + assert_matches_type(WaapAdvancedRuleDescriptorList, advanced_rule, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.advanced_rules.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + advanced_rule = await response.parse() + assert_matches_type(WaapAdvancedRuleDescriptorList, advanced_rule, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.waap.advanced_rules.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + advanced_rule = await response.parse() + assert_matches_type(WaapAdvancedRuleDescriptorList, advanced_rule, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/test_custom_page_sets.py b/tests/api_resources/waap/test_custom_page_sets.py new file mode 100644 index 00000000..1d26207e --- /dev/null +++ b/tests/api_resources/waap/test_custom_page_sets.py @@ -0,0 +1,620 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.waap import ( + WaapCustomPageSet, + WaapCustomPagePreview, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCustomPageSets: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Gcore) -> None: + custom_page_set = client.waap.custom_page_sets.create( + name="x", + ) + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Gcore) -> None: + custom_page_set = client.waap.custom_page_sets.create( + name="x", + block={ + "enabled": True, + "header": "xxx", + "logo": "logo", + "text": "xxxxxxxxxxxxxxxxxxxx", + "title": "xxx", + }, + block_csrf={ + "enabled": True, + "header": "xxx", + "logo": "logo", + "text": "xxxxxxxxxxxxxxxxxxxx", + "title": "xxx", + }, + captcha={ + "enabled": True, + "error": "xxxxxxxxxx", + "header": "xxx", + "logo": "logo", + "text": "xxxxxxxxxxxxxxxxxxxx", + "title": "xxx", + }, + cookie_disabled={ + "enabled": True, + "header": "xxx", + "text": "xxxxxxxxxxxxxxxxxxxx", + }, + domains=[1], + handshake={ + "enabled": True, + "header": "xxx", + "logo": "logo", + "title": "xxx", + }, + javascript_disabled={ + "enabled": True, + "header": "xxx", + "text": "xxxxxxxxxxxxxxxxxxxx", + }, + ) + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Gcore) -> None: + response = client.waap.custom_page_sets.with_raw_response.create( + name="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_page_set = response.parse() + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Gcore) -> None: + with client.waap.custom_page_sets.with_streaming_response.create( + name="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_page_set = response.parse() + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update(self, client: Gcore) -> None: + custom_page_set = client.waap.custom_page_sets.update( + set_id=0, + ) + assert custom_page_set is None + + @parametrize + def test_method_update_with_all_params(self, client: Gcore) -> None: + custom_page_set = client.waap.custom_page_sets.update( + set_id=0, + block={ + "enabled": True, + "header": "xxx", + "logo": "logo", + "text": "xxxxxxxxxxxxxxxxxxxx", + "title": "xxx", + }, + block_csrf={ + "enabled": True, + "header": "xxx", + "logo": "logo", + "text": "xxxxxxxxxxxxxxxxxxxx", + "title": "xxx", + }, + captcha={ + "enabled": True, + "error": "xxxxxxxxxx", + "header": "xxx", + "logo": "logo", + "text": "xxxxxxxxxxxxxxxxxxxx", + "title": "xxx", + }, + cookie_disabled={ + "enabled": True, + "header": "xxx", + "text": "xxxxxxxxxxxxxxxxxxxx", + }, + domains=[1], + handshake={ + "enabled": True, + "header": "xxx", + "logo": "logo", + "title": "xxx", + }, + javascript_disabled={ + "enabled": True, + "header": "xxx", + "text": "xxxxxxxxxxxxxxxxxxxx", + }, + name="x", + ) + assert custom_page_set is None + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.waap.custom_page_sets.with_raw_response.update( + set_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_page_set = response.parse() + assert custom_page_set is None + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.waap.custom_page_sets.with_streaming_response.update( + set_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_page_set = response.parse() + assert custom_page_set is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + custom_page_set = client.waap.custom_page_sets.list() + assert_matches_type(SyncOffsetPage[WaapCustomPageSet], custom_page_set, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + custom_page_set = client.waap.custom_page_sets.list( + ids=[0], + limit=0, + name="*example", + offset=0, + ordering="name", + ) + assert_matches_type(SyncOffsetPage[WaapCustomPageSet], custom_page_set, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.waap.custom_page_sets.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_page_set = response.parse() + assert_matches_type(SyncOffsetPage[WaapCustomPageSet], custom_page_set, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.waap.custom_page_sets.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_page_set = response.parse() + assert_matches_type(SyncOffsetPage[WaapCustomPageSet], custom_page_set, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + custom_page_set = client.waap.custom_page_sets.delete( + 0, + ) + assert custom_page_set is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.waap.custom_page_sets.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_page_set = response.parse() + assert custom_page_set is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.waap.custom_page_sets.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_page_set = response.parse() + assert custom_page_set is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + custom_page_set = client.waap.custom_page_sets.get( + 0, + ) + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.waap.custom_page_sets.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_page_set = response.parse() + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.waap.custom_page_sets.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_page_set = response.parse() + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_preview(self, client: Gcore) -> None: + custom_page_set = client.waap.custom_page_sets.preview( + page_type="block.html", + ) + assert_matches_type(WaapCustomPagePreview, custom_page_set, path=["response"]) + + @parametrize + def test_method_preview_with_all_params(self, client: Gcore) -> None: + custom_page_set = client.waap.custom_page_sets.preview( + page_type="block.html", + error="xxxxxxxxxx", + header="xxx", + logo="logo", + text="xxxxxxxxxxxxxxxxxxxx", + title="xxx", + ) + assert_matches_type(WaapCustomPagePreview, custom_page_set, path=["response"]) + + @parametrize + def test_raw_response_preview(self, client: Gcore) -> None: + response = client.waap.custom_page_sets.with_raw_response.preview( + page_type="block.html", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_page_set = response.parse() + assert_matches_type(WaapCustomPagePreview, custom_page_set, path=["response"]) + + @parametrize + def test_streaming_response_preview(self, client: Gcore) -> None: + with client.waap.custom_page_sets.with_streaming_response.preview( + page_type="block.html", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_page_set = response.parse() + assert_matches_type(WaapCustomPagePreview, custom_page_set, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncCustomPageSets: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncGcore) -> None: + custom_page_set = await async_client.waap.custom_page_sets.create( + name="x", + ) + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: + custom_page_set = await async_client.waap.custom_page_sets.create( + name="x", + block={ + "enabled": True, + "header": "xxx", + "logo": "logo", + "text": "xxxxxxxxxxxxxxxxxxxx", + "title": "xxx", + }, + block_csrf={ + "enabled": True, + "header": "xxx", + "logo": "logo", + "text": "xxxxxxxxxxxxxxxxxxxx", + "title": "xxx", + }, + captcha={ + "enabled": True, + "error": "xxxxxxxxxx", + "header": "xxx", + "logo": "logo", + "text": "xxxxxxxxxxxxxxxxxxxx", + "title": "xxx", + }, + cookie_disabled={ + "enabled": True, + "header": "xxx", + "text": "xxxxxxxxxxxxxxxxxxxx", + }, + domains=[1], + handshake={ + "enabled": True, + "header": "xxx", + "logo": "logo", + "title": "xxx", + }, + javascript_disabled={ + "enabled": True, + "header": "xxx", + "text": "xxxxxxxxxxxxxxxxxxxx", + }, + ) + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.custom_page_sets.with_raw_response.create( + name="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_page_set = await response.parse() + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: + async with async_client.waap.custom_page_sets.with_streaming_response.create( + name="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_page_set = await response.parse() + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + custom_page_set = await async_client.waap.custom_page_sets.update( + set_id=0, + ) + assert custom_page_set is None + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None: + custom_page_set = await async_client.waap.custom_page_sets.update( + set_id=0, + block={ + "enabled": True, + "header": "xxx", + "logo": "logo", + "text": "xxxxxxxxxxxxxxxxxxxx", + "title": "xxx", + }, + block_csrf={ + "enabled": True, + "header": "xxx", + "logo": "logo", + "text": "xxxxxxxxxxxxxxxxxxxx", + "title": "xxx", + }, + captcha={ + "enabled": True, + "error": "xxxxxxxxxx", + "header": "xxx", + "logo": "logo", + "text": "xxxxxxxxxxxxxxxxxxxx", + "title": "xxx", + }, + cookie_disabled={ + "enabled": True, + "header": "xxx", + "text": "xxxxxxxxxxxxxxxxxxxx", + }, + domains=[1], + handshake={ + "enabled": True, + "header": "xxx", + "logo": "logo", + "title": "xxx", + }, + javascript_disabled={ + "enabled": True, + "header": "xxx", + "text": "xxxxxxxxxxxxxxxxxxxx", + }, + name="x", + ) + assert custom_page_set is None + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.custom_page_sets.with_raw_response.update( + set_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_page_set = await response.parse() + assert custom_page_set is None + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.waap.custom_page_sets.with_streaming_response.update( + set_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_page_set = await response.parse() + assert custom_page_set is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + custom_page_set = await async_client.waap.custom_page_sets.list() + assert_matches_type(AsyncOffsetPage[WaapCustomPageSet], custom_page_set, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + custom_page_set = await async_client.waap.custom_page_sets.list( + ids=[0], + limit=0, + name="*example", + offset=0, + ordering="name", + ) + assert_matches_type(AsyncOffsetPage[WaapCustomPageSet], custom_page_set, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.custom_page_sets.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_page_set = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapCustomPageSet], custom_page_set, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.waap.custom_page_sets.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_page_set = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapCustomPageSet], custom_page_set, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + custom_page_set = await async_client.waap.custom_page_sets.delete( + 0, + ) + assert custom_page_set is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.custom_page_sets.with_raw_response.delete( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_page_set = await response.parse() + assert custom_page_set is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.waap.custom_page_sets.with_streaming_response.delete( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_page_set = await response.parse() + assert custom_page_set is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + custom_page_set = await async_client.waap.custom_page_sets.get( + 0, + ) + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.custom_page_sets.with_raw_response.get( + 0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_page_set = await response.parse() + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.waap.custom_page_sets.with_streaming_response.get( + 0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_page_set = await response.parse() + assert_matches_type(WaapCustomPageSet, custom_page_set, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_preview(self, async_client: AsyncGcore) -> None: + custom_page_set = await async_client.waap.custom_page_sets.preview( + page_type="block.html", + ) + assert_matches_type(WaapCustomPagePreview, custom_page_set, path=["response"]) + + @parametrize + async def test_method_preview_with_all_params(self, async_client: AsyncGcore) -> None: + custom_page_set = await async_client.waap.custom_page_sets.preview( + page_type="block.html", + error="xxxxxxxxxx", + header="xxx", + logo="logo", + text="xxxxxxxxxxxxxxxxxxxx", + title="xxx", + ) + assert_matches_type(WaapCustomPagePreview, custom_page_set, path=["response"]) + + @parametrize + async def test_raw_response_preview(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.custom_page_sets.with_raw_response.preview( + page_type="block.html", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + custom_page_set = await response.parse() + assert_matches_type(WaapCustomPagePreview, custom_page_set, path=["response"]) + + @parametrize + async def test_streaming_response_preview(self, async_client: AsyncGcore) -> None: + async with async_client.waap.custom_page_sets.with_streaming_response.preview( + page_type="block.html", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + custom_page_set = await response.parse() + assert_matches_type(WaapCustomPagePreview, custom_page_set, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/test_domains.py b/tests/api_resources/waap/test_domains.py new file mode 100644 index 00000000..9c3d9c26 --- /dev/null +++ b/tests/api_resources/waap/test_domains.py @@ -0,0 +1,442 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.waap import ( + WaapPolicyMode, + WaapSummaryDomain, + WaapDetailedDomain, + DomainListRuleSetsResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDomains: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_update(self, client: Gcore) -> None: + domain = client.waap.domains.update( + domain_id=1, + status="active", + ) + assert domain is None + + @parametrize + def test_raw_response_update(self, client: Gcore) -> None: + response = client.waap.domains.with_raw_response.update( + domain_id=1, + status="active", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain = response.parse() + assert domain is None + + @parametrize + def test_streaming_response_update(self, client: Gcore) -> None: + with client.waap.domains.with_streaming_response.update( + domain_id=1, + status="active", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain = response.parse() + assert domain is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Gcore) -> None: + domain = client.waap.domains.list() + assert_matches_type(SyncOffsetPage[WaapSummaryDomain], domain, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + domain = client.waap.domains.list( + ids=[1], + limit=0, + name="*example.com", + offset=0, + ordering="id", + status="active", + ) + assert_matches_type(SyncOffsetPage[WaapSummaryDomain], domain, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.waap.domains.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain = response.parse() + assert_matches_type(SyncOffsetPage[WaapSummaryDomain], domain, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.waap.domains.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain = response.parse() + assert_matches_type(SyncOffsetPage[WaapSummaryDomain], domain, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + domain = client.waap.domains.delete( + 1, + ) + assert domain is None + + @parametrize + def test_raw_response_delete(self, client: Gcore) -> None: + response = client.waap.domains.with_raw_response.delete( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain = response.parse() + assert domain is None + + @parametrize + def test_streaming_response_delete(self, client: Gcore) -> None: + with client.waap.domains.with_streaming_response.delete( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain = response.parse() + assert domain is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get(self, client: Gcore) -> None: + domain = client.waap.domains.get( + 1, + ) + assert_matches_type(WaapDetailedDomain, domain, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Gcore) -> None: + response = client.waap.domains.with_raw_response.get( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain = response.parse() + assert_matches_type(WaapDetailedDomain, domain, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Gcore) -> None: + with client.waap.domains.with_streaming_response.get( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain = response.parse() + assert_matches_type(WaapDetailedDomain, domain, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_rule_sets(self, client: Gcore) -> None: + domain = client.waap.domains.list_rule_sets( + 1, + ) + assert_matches_type(DomainListRuleSetsResponse, domain, path=["response"]) + + @parametrize + def test_raw_response_list_rule_sets(self, client: Gcore) -> None: + response = client.waap.domains.with_raw_response.list_rule_sets( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain = response.parse() + assert_matches_type(DomainListRuleSetsResponse, domain, path=["response"]) + + @parametrize + def test_streaming_response_list_rule_sets(self, client: Gcore) -> None: + with client.waap.domains.with_streaming_response.list_rule_sets( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain = response.parse() + assert_matches_type(DomainListRuleSetsResponse, domain, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_toggle_policy(self, client: Gcore) -> None: + domain = client.waap.domains.toggle_policy( + policy_id="policy_id", + domain_id=1, + ) + assert_matches_type(WaapPolicyMode, domain, path=["response"]) + + @parametrize + def test_raw_response_toggle_policy(self, client: Gcore) -> None: + response = client.waap.domains.with_raw_response.toggle_policy( + policy_id="policy_id", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain = response.parse() + assert_matches_type(WaapPolicyMode, domain, path=["response"]) + + @parametrize + def test_streaming_response_toggle_policy(self, client: Gcore) -> None: + with client.waap.domains.with_streaming_response.toggle_policy( + policy_id="policy_id", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain = response.parse() + assert_matches_type(WaapPolicyMode, domain, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_toggle_policy(self, client: Gcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): + client.waap.domains.with_raw_response.toggle_policy( + policy_id="", + domain_id=1, + ) + + +class TestAsyncDomains: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_update(self, async_client: AsyncGcore) -> None: + domain = await async_client.waap.domains.update( + domain_id=1, + status="active", + ) + assert domain is None + + @parametrize + async def test_raw_response_update(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.with_raw_response.update( + domain_id=1, + status="active", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain = await response.parse() + assert domain is None + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.with_streaming_response.update( + domain_id=1, + status="active", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain = await response.parse() + assert domain is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + domain = await async_client.waap.domains.list() + assert_matches_type(AsyncOffsetPage[WaapSummaryDomain], domain, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + domain = await async_client.waap.domains.list( + ids=[1], + limit=0, + name="*example.com", + offset=0, + ordering="id", + status="active", + ) + assert_matches_type(AsyncOffsetPage[WaapSummaryDomain], domain, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapSummaryDomain], domain, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapSummaryDomain], domain, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + domain = await async_client.waap.domains.delete( + 1, + ) + assert domain is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.with_raw_response.delete( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain = await response.parse() + assert domain is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.with_streaming_response.delete( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain = await response.parse() + assert domain is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + domain = await async_client.waap.domains.get( + 1, + ) + assert_matches_type(WaapDetailedDomain, domain, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.with_raw_response.get( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain = await response.parse() + assert_matches_type(WaapDetailedDomain, domain, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.with_streaming_response.get( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain = await response.parse() + assert_matches_type(WaapDetailedDomain, domain, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_rule_sets(self, async_client: AsyncGcore) -> None: + domain = await async_client.waap.domains.list_rule_sets( + 1, + ) + assert_matches_type(DomainListRuleSetsResponse, domain, path=["response"]) + + @parametrize + async def test_raw_response_list_rule_sets(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.with_raw_response.list_rule_sets( + 1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain = await response.parse() + assert_matches_type(DomainListRuleSetsResponse, domain, path=["response"]) + + @parametrize + async def test_streaming_response_list_rule_sets(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.with_streaming_response.list_rule_sets( + 1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain = await response.parse() + assert_matches_type(DomainListRuleSetsResponse, domain, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_toggle_policy(self, async_client: AsyncGcore) -> None: + domain = await async_client.waap.domains.toggle_policy( + policy_id="policy_id", + domain_id=1, + ) + assert_matches_type(WaapPolicyMode, domain, path=["response"]) + + @parametrize + async def test_raw_response_toggle_policy(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.domains.with_raw_response.toggle_policy( + policy_id="policy_id", + domain_id=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + domain = await response.parse() + assert_matches_type(WaapPolicyMode, domain, path=["response"]) + + @parametrize + async def test_streaming_response_toggle_policy(self, async_client: AsyncGcore) -> None: + async with async_client.waap.domains.with_streaming_response.toggle_policy( + policy_id="policy_id", + domain_id=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + domain = await response.parse() + assert_matches_type(WaapPolicyMode, domain, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_toggle_policy(self, async_client: AsyncGcore) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): + await async_client.waap.domains.with_raw_response.toggle_policy( + policy_id="", + domain_id=1, + ) diff --git a/tests/api_resources/waap/test_insights.py b/tests/api_resources/waap/test_insights.py new file mode 100644 index 00000000..009e880c --- /dev/null +++ b/tests/api_resources/waap/test_insights.py @@ -0,0 +1,99 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.waap import WaapInsightType + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestInsights: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list_types(self, client: Gcore) -> None: + insight = client.waap.insights.list_types() + assert_matches_type(SyncOffsetPage[WaapInsightType], insight, path=["response"]) + + @parametrize + def test_method_list_types_with_all_params(self, client: Gcore) -> None: + insight = client.waap.insights.list_types( + insight_frequency=1, + limit=0, + name="name", + offset=0, + ordering="name", + slug="slug", + ) + assert_matches_type(SyncOffsetPage[WaapInsightType], insight, path=["response"]) + + @parametrize + def test_raw_response_list_types(self, client: Gcore) -> None: + response = client.waap.insights.with_raw_response.list_types() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight = response.parse() + assert_matches_type(SyncOffsetPage[WaapInsightType], insight, path=["response"]) + + @parametrize + def test_streaming_response_list_types(self, client: Gcore) -> None: + with client.waap.insights.with_streaming_response.list_types() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight = response.parse() + assert_matches_type(SyncOffsetPage[WaapInsightType], insight, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncInsights: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list_types(self, async_client: AsyncGcore) -> None: + insight = await async_client.waap.insights.list_types() + assert_matches_type(AsyncOffsetPage[WaapInsightType], insight, path=["response"]) + + @parametrize + async def test_method_list_types_with_all_params(self, async_client: AsyncGcore) -> None: + insight = await async_client.waap.insights.list_types( + insight_frequency=1, + limit=0, + name="name", + offset=0, + ordering="name", + slug="slug", + ) + assert_matches_type(AsyncOffsetPage[WaapInsightType], insight, path=["response"]) + + @parametrize + async def test_raw_response_list_types(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.insights.with_raw_response.list_types() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + insight = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapInsightType], insight, path=["response"]) + + @parametrize + async def test_streaming_response_list_types(self, async_client: AsyncGcore) -> None: + async with async_client.waap.insights.with_streaming_response.list_types() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + insight = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapInsightType], insight, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/test_ip_info.py b/tests/api_resources/waap/test_ip_info.py new file mode 100644 index 00000000..e3b42484 --- /dev/null +++ b/tests/api_resources/waap/test_ip_info.py @@ -0,0 +1,553 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.types.waap import ( + WaapIPInfo, + WaapIPDDOSInfoModel, + IPInfoGetTopURLsResponse, + IPInfoGetTopUserAgentsResponse, + IPInfoGetBlockedRequestsResponse, + IPInfoGetTopUserSessionsResponse, + IPInfoGetAttackTimeSeriesResponse, + IPInfoListAttackedCountriesResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestIPInfo: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_attack_time_series(self, client: Gcore) -> None: + ip_info = client.waap.ip_info.get_attack_time_series( + ip="192.168.1.1", + ) + assert_matches_type(IPInfoGetAttackTimeSeriesResponse, ip_info, path=["response"]) + + @parametrize + def test_raw_response_get_attack_time_series(self, client: Gcore) -> None: + response = client.waap.ip_info.with_raw_response.get_attack_time_series( + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = response.parse() + assert_matches_type(IPInfoGetAttackTimeSeriesResponse, ip_info, path=["response"]) + + @parametrize + def test_streaming_response_get_attack_time_series(self, client: Gcore) -> None: + with client.waap.ip_info.with_streaming_response.get_attack_time_series( + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = response.parse() + assert_matches_type(IPInfoGetAttackTimeSeriesResponse, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_blocked_requests(self, client: Gcore) -> None: + ip_info = client.waap.ip_info.get_blocked_requests( + domain_id=1, + ip="192.168.1.1", + ) + assert_matches_type(IPInfoGetBlockedRequestsResponse, ip_info, path=["response"]) + + @parametrize + def test_raw_response_get_blocked_requests(self, client: Gcore) -> None: + response = client.waap.ip_info.with_raw_response.get_blocked_requests( + domain_id=1, + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = response.parse() + assert_matches_type(IPInfoGetBlockedRequestsResponse, ip_info, path=["response"]) + + @parametrize + def test_streaming_response_get_blocked_requests(self, client: Gcore) -> None: + with client.waap.ip_info.with_streaming_response.get_blocked_requests( + domain_id=1, + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = response.parse() + assert_matches_type(IPInfoGetBlockedRequestsResponse, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_ddos_attack_series(self, client: Gcore) -> None: + ip_info = client.waap.ip_info.get_ddos_attack_series( + ip="192.168.1.1", + ) + assert_matches_type(WaapIPDDOSInfoModel, ip_info, path=["response"]) + + @parametrize + def test_raw_response_get_ddos_attack_series(self, client: Gcore) -> None: + response = client.waap.ip_info.with_raw_response.get_ddos_attack_series( + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = response.parse() + assert_matches_type(WaapIPDDOSInfoModel, ip_info, path=["response"]) + + @parametrize + def test_streaming_response_get_ddos_attack_series(self, client: Gcore) -> None: + with client.waap.ip_info.with_streaming_response.get_ddos_attack_series( + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = response.parse() + assert_matches_type(WaapIPDDOSInfoModel, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_ip_info(self, client: Gcore) -> None: + ip_info = client.waap.ip_info.get_ip_info( + ip="192.168.1.1", + ) + assert_matches_type(WaapIPInfo, ip_info, path=["response"]) + + @parametrize + def test_raw_response_get_ip_info(self, client: Gcore) -> None: + response = client.waap.ip_info.with_raw_response.get_ip_info( + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = response.parse() + assert_matches_type(WaapIPInfo, ip_info, path=["response"]) + + @parametrize + def test_streaming_response_get_ip_info(self, client: Gcore) -> None: + with client.waap.ip_info.with_streaming_response.get_ip_info( + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = response.parse() + assert_matches_type(WaapIPInfo, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_top_urls(self, client: Gcore) -> None: + ip_info = client.waap.ip_info.get_top_urls( + domain_id=1, + ip="192.168.1.1", + ) + assert_matches_type(IPInfoGetTopURLsResponse, ip_info, path=["response"]) + + @parametrize + def test_raw_response_get_top_urls(self, client: Gcore) -> None: + response = client.waap.ip_info.with_raw_response.get_top_urls( + domain_id=1, + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = response.parse() + assert_matches_type(IPInfoGetTopURLsResponse, ip_info, path=["response"]) + + @parametrize + def test_streaming_response_get_top_urls(self, client: Gcore) -> None: + with client.waap.ip_info.with_streaming_response.get_top_urls( + domain_id=1, + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = response.parse() + assert_matches_type(IPInfoGetTopURLsResponse, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_top_user_agents(self, client: Gcore) -> None: + ip_info = client.waap.ip_info.get_top_user_agents( + domain_id=1, + ip="192.168.1.1", + ) + assert_matches_type(IPInfoGetTopUserAgentsResponse, ip_info, path=["response"]) + + @parametrize + def test_raw_response_get_top_user_agents(self, client: Gcore) -> None: + response = client.waap.ip_info.with_raw_response.get_top_user_agents( + domain_id=1, + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = response.parse() + assert_matches_type(IPInfoGetTopUserAgentsResponse, ip_info, path=["response"]) + + @parametrize + def test_streaming_response_get_top_user_agents(self, client: Gcore) -> None: + with client.waap.ip_info.with_streaming_response.get_top_user_agents( + domain_id=1, + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = response.parse() + assert_matches_type(IPInfoGetTopUserAgentsResponse, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_get_top_user_sessions(self, client: Gcore) -> None: + ip_info = client.waap.ip_info.get_top_user_sessions( + domain_id=1, + ip="192.168.1.1", + ) + assert_matches_type(IPInfoGetTopUserSessionsResponse, ip_info, path=["response"]) + + @parametrize + def test_raw_response_get_top_user_sessions(self, client: Gcore) -> None: + response = client.waap.ip_info.with_raw_response.get_top_user_sessions( + domain_id=1, + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = response.parse() + assert_matches_type(IPInfoGetTopUserSessionsResponse, ip_info, path=["response"]) + + @parametrize + def test_streaming_response_get_top_user_sessions(self, client: Gcore) -> None: + with client.waap.ip_info.with_streaming_response.get_top_user_sessions( + domain_id=1, + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = response.parse() + assert_matches_type(IPInfoGetTopUserSessionsResponse, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_attacked_countries(self, client: Gcore) -> None: + ip_info = client.waap.ip_info.list_attacked_countries( + ip="192.168.1.1", + ) + assert_matches_type(IPInfoListAttackedCountriesResponse, ip_info, path=["response"]) + + @parametrize + def test_raw_response_list_attacked_countries(self, client: Gcore) -> None: + response = client.waap.ip_info.with_raw_response.list_attacked_countries( + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = response.parse() + assert_matches_type(IPInfoListAttackedCountriesResponse, ip_info, path=["response"]) + + @parametrize + def test_streaming_response_list_attacked_countries(self, client: Gcore) -> None: + with client.waap.ip_info.with_streaming_response.list_attacked_countries( + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = response.parse() + assert_matches_type(IPInfoListAttackedCountriesResponse, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncIPInfo: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_attack_time_series(self, async_client: AsyncGcore) -> None: + ip_info = await async_client.waap.ip_info.get_attack_time_series( + ip="192.168.1.1", + ) + assert_matches_type(IPInfoGetAttackTimeSeriesResponse, ip_info, path=["response"]) + + @parametrize + async def test_raw_response_get_attack_time_series(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.ip_info.with_raw_response.get_attack_time_series( + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = await response.parse() + assert_matches_type(IPInfoGetAttackTimeSeriesResponse, ip_info, path=["response"]) + + @parametrize + async def test_streaming_response_get_attack_time_series(self, async_client: AsyncGcore) -> None: + async with async_client.waap.ip_info.with_streaming_response.get_attack_time_series( + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = await response.parse() + assert_matches_type(IPInfoGetAttackTimeSeriesResponse, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_blocked_requests(self, async_client: AsyncGcore) -> None: + ip_info = await async_client.waap.ip_info.get_blocked_requests( + domain_id=1, + ip="192.168.1.1", + ) + assert_matches_type(IPInfoGetBlockedRequestsResponse, ip_info, path=["response"]) + + @parametrize + async def test_raw_response_get_blocked_requests(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.ip_info.with_raw_response.get_blocked_requests( + domain_id=1, + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = await response.parse() + assert_matches_type(IPInfoGetBlockedRequestsResponse, ip_info, path=["response"]) + + @parametrize + async def test_streaming_response_get_blocked_requests(self, async_client: AsyncGcore) -> None: + async with async_client.waap.ip_info.with_streaming_response.get_blocked_requests( + domain_id=1, + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = await response.parse() + assert_matches_type(IPInfoGetBlockedRequestsResponse, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_ddos_attack_series(self, async_client: AsyncGcore) -> None: + ip_info = await async_client.waap.ip_info.get_ddos_attack_series( + ip="192.168.1.1", + ) + assert_matches_type(WaapIPDDOSInfoModel, ip_info, path=["response"]) + + @parametrize + async def test_raw_response_get_ddos_attack_series(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.ip_info.with_raw_response.get_ddos_attack_series( + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = await response.parse() + assert_matches_type(WaapIPDDOSInfoModel, ip_info, path=["response"]) + + @parametrize + async def test_streaming_response_get_ddos_attack_series(self, async_client: AsyncGcore) -> None: + async with async_client.waap.ip_info.with_streaming_response.get_ddos_attack_series( + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = await response.parse() + assert_matches_type(WaapIPDDOSInfoModel, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_ip_info(self, async_client: AsyncGcore) -> None: + ip_info = await async_client.waap.ip_info.get_ip_info( + ip="192.168.1.1", + ) + assert_matches_type(WaapIPInfo, ip_info, path=["response"]) + + @parametrize + async def test_raw_response_get_ip_info(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.ip_info.with_raw_response.get_ip_info( + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = await response.parse() + assert_matches_type(WaapIPInfo, ip_info, path=["response"]) + + @parametrize + async def test_streaming_response_get_ip_info(self, async_client: AsyncGcore) -> None: + async with async_client.waap.ip_info.with_streaming_response.get_ip_info( + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = await response.parse() + assert_matches_type(WaapIPInfo, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_top_urls(self, async_client: AsyncGcore) -> None: + ip_info = await async_client.waap.ip_info.get_top_urls( + domain_id=1, + ip="192.168.1.1", + ) + assert_matches_type(IPInfoGetTopURLsResponse, ip_info, path=["response"]) + + @parametrize + async def test_raw_response_get_top_urls(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.ip_info.with_raw_response.get_top_urls( + domain_id=1, + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = await response.parse() + assert_matches_type(IPInfoGetTopURLsResponse, ip_info, path=["response"]) + + @parametrize + async def test_streaming_response_get_top_urls(self, async_client: AsyncGcore) -> None: + async with async_client.waap.ip_info.with_streaming_response.get_top_urls( + domain_id=1, + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = await response.parse() + assert_matches_type(IPInfoGetTopURLsResponse, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_top_user_agents(self, async_client: AsyncGcore) -> None: + ip_info = await async_client.waap.ip_info.get_top_user_agents( + domain_id=1, + ip="192.168.1.1", + ) + assert_matches_type(IPInfoGetTopUserAgentsResponse, ip_info, path=["response"]) + + @parametrize + async def test_raw_response_get_top_user_agents(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.ip_info.with_raw_response.get_top_user_agents( + domain_id=1, + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = await response.parse() + assert_matches_type(IPInfoGetTopUserAgentsResponse, ip_info, path=["response"]) + + @parametrize + async def test_streaming_response_get_top_user_agents(self, async_client: AsyncGcore) -> None: + async with async_client.waap.ip_info.with_streaming_response.get_top_user_agents( + domain_id=1, + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = await response.parse() + assert_matches_type(IPInfoGetTopUserAgentsResponse, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_get_top_user_sessions(self, async_client: AsyncGcore) -> None: + ip_info = await async_client.waap.ip_info.get_top_user_sessions( + domain_id=1, + ip="192.168.1.1", + ) + assert_matches_type(IPInfoGetTopUserSessionsResponse, ip_info, path=["response"]) + + @parametrize + async def test_raw_response_get_top_user_sessions(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.ip_info.with_raw_response.get_top_user_sessions( + domain_id=1, + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = await response.parse() + assert_matches_type(IPInfoGetTopUserSessionsResponse, ip_info, path=["response"]) + + @parametrize + async def test_streaming_response_get_top_user_sessions(self, async_client: AsyncGcore) -> None: + async with async_client.waap.ip_info.with_streaming_response.get_top_user_sessions( + domain_id=1, + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = await response.parse() + assert_matches_type(IPInfoGetTopUserSessionsResponse, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_attacked_countries(self, async_client: AsyncGcore) -> None: + ip_info = await async_client.waap.ip_info.list_attacked_countries( + ip="192.168.1.1", + ) + assert_matches_type(IPInfoListAttackedCountriesResponse, ip_info, path=["response"]) + + @parametrize + async def test_raw_response_list_attacked_countries(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.ip_info.with_raw_response.list_attacked_countries( + ip="192.168.1.1", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + ip_info = await response.parse() + assert_matches_type(IPInfoListAttackedCountriesResponse, ip_info, path=["response"]) + + @parametrize + async def test_streaming_response_list_attacked_countries(self, async_client: AsyncGcore) -> None: + async with async_client.waap.ip_info.with_streaming_response.list_attacked_countries( + ip="192.168.1.1", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + ip_info = await response.parse() + assert_matches_type(IPInfoListAttackedCountriesResponse, ip_info, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/test_organizations.py b/tests/api_resources/waap/test_organizations.py new file mode 100644 index 00000000..ce01cf82 --- /dev/null +++ b/tests/api_resources/waap/test_organizations.py @@ -0,0 +1,95 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.waap import WaapOrganization + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestOrganizations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + organization = client.waap.organizations.list() + assert_matches_type(SyncOffsetPage[WaapOrganization], organization, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + organization = client.waap.organizations.list( + limit=0, + name="Comcast", + offset=0, + ordering="name", + ) + assert_matches_type(SyncOffsetPage[WaapOrganization], organization, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.waap.organizations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = response.parse() + assert_matches_type(SyncOffsetPage[WaapOrganization], organization, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.waap.organizations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = response.parse() + assert_matches_type(SyncOffsetPage[WaapOrganization], organization, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncOrganizations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + organization = await async_client.waap.organizations.list() + assert_matches_type(AsyncOffsetPage[WaapOrganization], organization, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + organization = await async_client.waap.organizations.list( + limit=0, + name="Comcast", + offset=0, + ordering="name", + ) + assert_matches_type(AsyncOffsetPage[WaapOrganization], organization, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.organizations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + organization = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapOrganization], organization, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.waap.organizations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + organization = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapOrganization], organization, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/test_statistics.py b/tests/api_resources/waap/test_statistics.py new file mode 100644 index 00000000..513e819d --- /dev/null +++ b/tests/api_resources/waap/test_statistics.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore._utils import parse_datetime +from gcore.types.waap import WaapStatisticsSeries + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestStatistics: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get_usage_series(self, client: Gcore) -> None: + statistic = client.waap.statistics.get_usage_series( + from_=parse_datetime("2024-12-14T12:00:00Z"), + granularity="1h", + metrics=["total_bytes"], + to=parse_datetime("2024-12-14T12:00:00Z"), + ) + assert_matches_type(WaapStatisticsSeries, statistic, path=["response"]) + + @parametrize + def test_raw_response_get_usage_series(self, client: Gcore) -> None: + response = client.waap.statistics.with_raw_response.get_usage_series( + from_=parse_datetime("2024-12-14T12:00:00Z"), + granularity="1h", + metrics=["total_bytes"], + to=parse_datetime("2024-12-14T12:00:00Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = response.parse() + assert_matches_type(WaapStatisticsSeries, statistic, path=["response"]) + + @parametrize + def test_streaming_response_get_usage_series(self, client: Gcore) -> None: + with client.waap.statistics.with_streaming_response.get_usage_series( + from_=parse_datetime("2024-12-14T12:00:00Z"), + granularity="1h", + metrics=["total_bytes"], + to=parse_datetime("2024-12-14T12:00:00Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = response.parse() + assert_matches_type(WaapStatisticsSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncStatistics: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get_usage_series(self, async_client: AsyncGcore) -> None: + statistic = await async_client.waap.statistics.get_usage_series( + from_=parse_datetime("2024-12-14T12:00:00Z"), + granularity="1h", + metrics=["total_bytes"], + to=parse_datetime("2024-12-14T12:00:00Z"), + ) + assert_matches_type(WaapStatisticsSeries, statistic, path=["response"]) + + @parametrize + async def test_raw_response_get_usage_series(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.statistics.with_raw_response.get_usage_series( + from_=parse_datetime("2024-12-14T12:00:00Z"), + granularity="1h", + metrics=["total_bytes"], + to=parse_datetime("2024-12-14T12:00:00Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + statistic = await response.parse() + assert_matches_type(WaapStatisticsSeries, statistic, path=["response"]) + + @parametrize + async def test_streaming_response_get_usage_series(self, async_client: AsyncGcore) -> None: + async with async_client.waap.statistics.with_streaming_response.get_usage_series( + from_=parse_datetime("2024-12-14T12:00:00Z"), + granularity="1h", + metrics=["total_bytes"], + to=parse_datetime("2024-12-14T12:00:00Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + statistic = await response.parse() + assert_matches_type(WaapStatisticsSeries, statistic, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/waap/test_tags.py b/tests/api_resources/waap/test_tags.py new file mode 100644 index 00000000..cb4474d8 --- /dev/null +++ b/tests/api_resources/waap/test_tags.py @@ -0,0 +1,99 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from gcore import Gcore, AsyncGcore +from tests.utils import assert_matches_type +from gcore.pagination import SyncOffsetPage, AsyncOffsetPage +from gcore.types.waap import WaapTag + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTags: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + tag = client.waap.tags.list() + assert_matches_type(SyncOffsetPage[WaapTag], tag, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Gcore) -> None: + tag = client.waap.tags.list( + limit=0, + name="xss", + offset=0, + ordering="name", + readable_name="Cross-Site Scripting", + reserved=True, + ) + assert_matches_type(SyncOffsetPage[WaapTag], tag, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Gcore) -> None: + response = client.waap.tags.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + tag = response.parse() + assert_matches_type(SyncOffsetPage[WaapTag], tag, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Gcore) -> None: + with client.waap.tags.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + tag = response.parse() + assert_matches_type(SyncOffsetPage[WaapTag], tag, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncTags: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + tag = await async_client.waap.tags.list() + assert_matches_type(AsyncOffsetPage[WaapTag], tag, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: + tag = await async_client.waap.tags.list( + limit=0, + name="xss", + offset=0, + ordering="name", + readable_name="Cross-Site Scripting", + reserved=True, + ) + assert_matches_type(AsyncOffsetPage[WaapTag], tag, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncGcore) -> None: + response = await async_client.waap.tags.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + tag = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapTag], tag, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: + async with async_client.waap.tags.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + tag = await response.parse() + assert_matches_type(AsyncOffsetPage[WaapTag], tag, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..36a0402c --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,84 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +import logging +from typing import TYPE_CHECKING, Iterator, AsyncIterator + +import httpx +import pytest +from pytest_asyncio import is_async_test + +from gcore import Gcore, AsyncGcore, DefaultAioHttpClient +from gcore._utils import is_dict + +if TYPE_CHECKING: + from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] + +pytest.register_assert_rewrite("tests.utils") + +logging.getLogger("gcore").setLevel(logging.DEBUG) + + +# automatically add `pytest.mark.asyncio()` to all of our async tests +# so we don't have to add that boilerplate everywhere +def pytest_collection_modifyitems(items: list[pytest.Function]) -> None: + pytest_asyncio_tests = (item for item in items if is_async_test(item)) + session_scope_marker = pytest.mark.asyncio(loop_scope="session") + for async_test in pytest_asyncio_tests: + async_test.add_marker(session_scope_marker, append=False) + + # We skip tests that use both the aiohttp client and respx_mock as respx_mock + # doesn't support custom transports. + for item in items: + if "async_client" not in item.fixturenames or "respx_mock" not in item.fixturenames: + continue + + if not hasattr(item, "callspec"): + continue + + async_client_param = item.callspec.params.get("async_client") + if is_dict(async_client_param) and async_client_param.get("http_client") == "aiohttp": + item.add_marker(pytest.mark.skip(reason="aiohttp client is not compatible with respx_mock")) + + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + +api_key = "My API Key" + + +@pytest.fixture(scope="session") +def client(request: FixtureRequest) -> Iterator[Gcore]: + strict = getattr(request, "param", True) + if not isinstance(strict, bool): + raise TypeError(f"Unexpected fixture parameter type {type(strict)}, expected {bool}") + + with Gcore(base_url=base_url, api_key=api_key, _strict_response_validation=strict) as client: + yield client + + +@pytest.fixture(scope="session") +async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncGcore]: + param = getattr(request, "param", True) + + # defaults + strict = True + http_client: None | httpx.AsyncClient = None + + if isinstance(param, bool): + strict = param + elif is_dict(param): + strict = param.get("strict", True) + assert isinstance(strict, bool) + + http_client_type = param.get("http_client", "httpx") + if http_client_type == "aiohttp": + http_client = DefaultAioHttpClient() + else: + raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict") + + async with AsyncGcore( + base_url=base_url, api_key=api_key, _strict_response_validation=strict, http_client=http_client + ) as client: + yield client diff --git a/tests/sample_file.txt b/tests/sample_file.txt new file mode 100644 index 00000000..af5626b4 --- /dev/null +++ b/tests/sample_file.txt @@ -0,0 +1 @@ +Hello, world! diff --git a/tests/test_client.py b/tests/test_client.py new file mode 100644 index 00000000..67601f11 --- /dev/null +++ b/tests/test_client.py @@ -0,0 +1,1934 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import gc +import os +import sys +import json +import asyncio +import inspect +import dataclasses +import tracemalloc +from typing import Any, Union, TypeVar, Callable, Iterable, Iterator, Optional, Coroutine, cast +from unittest import mock +from typing_extensions import Literal, AsyncIterator, override + +import httpx +import pytest +from respx import MockRouter +from pydantic import ValidationError + +from gcore import Gcore, AsyncGcore, APIResponseValidationError +from gcore._types import Omit +from gcore._utils import asyncify +from gcore._models import BaseModel, FinalRequestOptions +from gcore._exceptions import GcoreError, APIStatusError, APITimeoutError, APIResponseValidationError +from gcore._base_client import ( + DEFAULT_TIMEOUT, + HTTPX_DEFAULT_TIMEOUT, + BaseClient, + OtherPlatform, + DefaultHttpxClient, + DefaultAsyncHttpxClient, + get_platform, + make_request_options, +) + +from .utils import update_env + +T = TypeVar("T") +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") +api_key = "My API Key" + + +def _get_params(client: BaseClient[Any, Any]) -> dict[str, str]: + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + url = httpx.URL(request.url) + return dict(url.params) + + +def _low_retry_timeout(*_args: Any, **_kwargs: Any) -> float: + return 0.1 + + +def mirror_request_content(request: httpx.Request) -> httpx.Response: + return httpx.Response(200, content=request.content) + + +# note: we can't use the httpx.MockTransport class as it consumes the request +# body itself, which means we can't test that the body is read lazily +class MockTransport(httpx.BaseTransport, httpx.AsyncBaseTransport): + def __init__( + self, + handler: Callable[[httpx.Request], httpx.Response] + | Callable[[httpx.Request], Coroutine[Any, Any, httpx.Response]], + ) -> None: + self.handler = handler + + @override + def handle_request( + self, + request: httpx.Request, + ) -> httpx.Response: + assert not inspect.iscoroutinefunction(self.handler), "handler must not be a coroutine function" + assert inspect.isfunction(self.handler), "handler must be a function" + return self.handler(request) + + @override + async def handle_async_request( + self, + request: httpx.Request, + ) -> httpx.Response: + assert inspect.iscoroutinefunction(self.handler), "handler must be a coroutine function" + return await self.handler(request) + + +@dataclasses.dataclass +class Counter: + value: int = 0 + + +def _make_sync_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> Iterator[T]: + for item in iterable: + if counter: + counter.value += 1 + yield item + + +async def _make_async_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> AsyncIterator[T]: + for item in iterable: + if counter: + counter.value += 1 + yield item + + +def _get_open_connections(client: Gcore | AsyncGcore) -> int: + transport = client._client._transport + assert isinstance(transport, httpx.HTTPTransport) or isinstance(transport, httpx.AsyncHTTPTransport) + + pool = transport._pool + return len(pool._requests) + + +class TestGcore: + @pytest.mark.respx(base_url=base_url) + def test_raw_response(self, respx_mock: MockRouter, client: Gcore) -> None: + respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = client.post("/foo", cast_to=httpx.Response) + assert response.status_code == 200 + assert isinstance(response, httpx.Response) + assert response.json() == {"foo": "bar"} + + @pytest.mark.respx(base_url=base_url) + def test_raw_response_for_binary(self, respx_mock: MockRouter, client: Gcore) -> None: + respx_mock.post("/foo").mock( + return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') + ) + + response = client.post("/foo", cast_to=httpx.Response) + assert response.status_code == 200 + assert isinstance(response, httpx.Response) + assert response.json() == {"foo": "bar"} + + def test_copy(self, client: Gcore) -> None: + copied = client.copy() + assert id(copied) != id(client) + + copied = client.copy(api_key="another My API Key") + assert copied.api_key == "another My API Key" + assert client.api_key == "My API Key" + + def test_copy_default_options(self, client: Gcore) -> None: + # options that have a default are overridden correctly + copied = client.copy(max_retries=7) + assert copied.max_retries == 7 + assert client.max_retries == 2 + + copied2 = copied.copy(max_retries=6) + assert copied2.max_retries == 6 + assert copied.max_retries == 7 + + # timeout + assert isinstance(client.timeout, httpx.Timeout) + copied = client.copy(timeout=None) + assert copied.timeout is None + assert isinstance(client.timeout, httpx.Timeout) + + def test_copy_default_headers(self) -> None: + client = Gcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} + ) + assert client.default_headers["X-Foo"] == "bar" + + # does not override the already given value when not specified + copied = client.copy() + assert copied.default_headers["X-Foo"] == "bar" + + # merges already given headers + copied = client.copy(default_headers={"X-Bar": "stainless"}) + assert copied.default_headers["X-Foo"] == "bar" + assert copied.default_headers["X-Bar"] == "stainless" + + # uses new values for any already given headers + copied = client.copy(default_headers={"X-Foo": "stainless"}) + assert copied.default_headers["X-Foo"] == "stainless" + + # set_default_headers + + # completely overrides already set values + copied = client.copy(set_default_headers={}) + assert copied.default_headers.get("X-Foo") is None + + copied = client.copy(set_default_headers={"X-Bar": "Robert"}) + assert copied.default_headers["X-Bar"] == "Robert" + + with pytest.raises( + ValueError, + match="`default_headers` and `set_default_headers` arguments are mutually exclusive", + ): + client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + client.close() + + def test_copy_default_query(self) -> None: + client = Gcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"foo": "bar"} + ) + assert _get_params(client)["foo"] == "bar" + + # does not override the already given value when not specified + copied = client.copy() + assert _get_params(copied)["foo"] == "bar" + + # merges already given params + copied = client.copy(default_query={"bar": "stainless"}) + params = _get_params(copied) + assert params["foo"] == "bar" + assert params["bar"] == "stainless" + + # uses new values for any already given headers + copied = client.copy(default_query={"foo": "stainless"}) + assert _get_params(copied)["foo"] == "stainless" + + # set_default_query + + # completely overrides already set values + copied = client.copy(set_default_query={}) + assert _get_params(copied) == {} + + copied = client.copy(set_default_query={"bar": "Robert"}) + assert _get_params(copied)["bar"] == "Robert" + + with pytest.raises( + ValueError, + # TODO: update + match="`default_query` and `set_default_query` arguments are mutually exclusive", + ): + client.copy(set_default_query={}, default_query={"foo": "Bar"}) + + client.close() + + def test_copy_signature(self, client: Gcore) -> None: + # ensure the same parameters that can be passed to the client are defined in the `.copy()` method + init_signature = inspect.signature( + # mypy doesn't like that we access the `__init__` property. + client.__init__, # type: ignore[misc] + ) + copy_signature = inspect.signature(client.copy) + exclude_params = {"transport", "proxies", "_strict_response_validation"} + + for name in init_signature.parameters.keys(): + if name in exclude_params: + continue + + copy_param = copy_signature.parameters.get(name) + assert copy_param is not None, f"copy() signature is missing the {name} param" + + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") + def test_copy_build_request(self, client: Gcore) -> None: + options = FinalRequestOptions(method="get", url="/foo") + + def build_request(options: FinalRequestOptions) -> None: + client_copy = client.copy() + client_copy._build_request(options) + + # ensure that the machinery is warmed up before tracing starts. + build_request(options) + gc.collect() + + tracemalloc.start(1000) + + snapshot_before = tracemalloc.take_snapshot() + + ITERATIONS = 10 + for _ in range(ITERATIONS): + build_request(options) + + gc.collect() + snapshot_after = tracemalloc.take_snapshot() + + tracemalloc.stop() + + def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.StatisticDiff) -> None: + if diff.count == 0: + # Avoid false positives by considering only leaks (i.e. allocations that persist). + return + + if diff.count % ITERATIONS != 0: + # Avoid false positives by considering only leaks that appear per iteration. + return + + for frame in diff.traceback: + if any( + frame.filename.endswith(fragment) + for fragment in [ + # to_raw_response_wrapper leaks through the @functools.wraps() decorator. + # + # removing the decorator fixes the leak for reasons we don't understand. + "gcore/_legacy_response.py", + "gcore/_response.py", + # pydantic.BaseModel.model_dump || pydantic.BaseModel.dict leak memory for some reason. + "gcore/_compat.py", + # Standard library leaks we don't care about. + "/logging/__init__.py", + ] + ): + return + + leaks.append(diff) + + leaks: list[tracemalloc.StatisticDiff] = [] + for diff in snapshot_after.compare_to(snapshot_before, "traceback"): + add_leak(leaks, diff) + if leaks: + for leak in leaks: + print("MEMORY LEAK:", leak) + for frame in leak.traceback: + print(frame) + raise AssertionError() + + def test_request_timeout(self, client: Gcore) -> None: + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == DEFAULT_TIMEOUT + + request = client._build_request(FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0))) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == httpx.Timeout(100.0) + + def test_client_timeout_option(self) -> None: + client = Gcore(base_url=base_url, api_key=api_key, _strict_response_validation=True, timeout=httpx.Timeout(0)) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == httpx.Timeout(0) + + client.close() + + def test_http_client_timeout_option(self) -> None: + # custom timeout given to the httpx client should be used + with httpx.Client(timeout=None) as http_client: + client = Gcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == httpx.Timeout(None) + + client.close() + + # no timeout given to the httpx client should not use the httpx default + with httpx.Client() as http_client: + client = Gcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == DEFAULT_TIMEOUT + + client.close() + + # explicitly passing the default timeout currently results in it being ignored + with httpx.Client(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: + client = Gcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == DEFAULT_TIMEOUT # our default + + client.close() + + async def test_invalid_http_client(self) -> None: + with pytest.raises(TypeError, match="Invalid `http_client` arg"): + async with httpx.AsyncClient() as http_client: + Gcore( + base_url=base_url, + api_key=api_key, + _strict_response_validation=True, + http_client=cast(Any, http_client), + ) + + def test_default_headers_option(self) -> None: + test_client = Gcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} + ) + request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("x-foo") == "bar" + assert request.headers.get("x-stainless-lang") == "python" + + test_client2 = Gcore( + base_url=base_url, + api_key=api_key, + _strict_response_validation=True, + default_headers={ + "X-Foo": "stainless", + "X-Stainless-Lang": "my-overriding-header", + }, + ) + request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("x-foo") == "stainless" + assert request.headers.get("x-stainless-lang") == "my-overriding-header" + + test_client.close() + test_client2.close() + + def test_validate_headers(self) -> None: + client = Gcore(base_url=base_url, api_key=api_key, _strict_response_validation=True) + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("Authorization") == f"APIKey {api_key}" + + with pytest.raises(GcoreError): + with update_env(**{"GCORE_API_KEY": Omit()}): + client2 = Gcore(base_url=base_url, api_key=None, _strict_response_validation=True) + _ = client2 + + def test_default_query_option(self) -> None: + client = Gcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} + ) + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + url = httpx.URL(request.url) + assert dict(url.params) == {"query_param": "bar"} + + request = client._build_request( + FinalRequestOptions( + method="get", + url="/foo", + params={"foo": "baz", "query_param": "overridden"}, + ) + ) + url = httpx.URL(request.url) + assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} + + client.close() + + def test_cloud_project_id_client_params(self, client: Gcore) -> None: + # Test with base client (no custom params) + with pytest.raises(ValueError, match="Missing cloud_project_id argument;"): + client.cloud.projects.update() + + client = Gcore(base_url=base_url, api_key=api_key, _strict_response_validation=True, cloud_project_id=0) + with client as c2: + c2.cloud.projects.update() + + def test_cloud_region_id_client_params(self, client: Gcore) -> None: + # Test with base client (no custom params) + with pytest.raises(ValueError, match="Missing cloud_region_id argument;"): + client.cloud.regions.get() + + client = Gcore(base_url=base_url, api_key=api_key, _strict_response_validation=True, cloud_region_id=0) + with client as c2: + c2.cloud.regions.get() + + def test_request_extra_json(self, client: Gcore) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar"}, + extra_json={"baz": False}, + ), + ) + data = json.loads(request.content.decode("utf-8")) + assert data == {"foo": "bar", "baz": False} + + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + extra_json={"baz": False}, + ), + ) + data = json.loads(request.content.decode("utf-8")) + assert data == {"baz": False} + + # `extra_json` takes priority over `json_data` when keys clash + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar", "baz": True}, + extra_json={"baz": None}, + ), + ) + data = json.loads(request.content.decode("utf-8")) + assert data == {"foo": "bar", "baz": None} + + def test_request_extra_headers(self, client: Gcore) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options(extra_headers={"X-Foo": "Foo"}), + ), + ) + assert request.headers.get("X-Foo") == "Foo" + + # `extra_headers` takes priority over `default_headers` when keys clash + request = client.with_options(default_headers={"X-Bar": "true"})._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + extra_headers={"X-Bar": "false"}, + ), + ), + ) + assert request.headers.get("X-Bar") == "false" + + def test_request_extra_query(self, client: Gcore) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + extra_query={"my_query_param": "Foo"}, + ), + ), + ) + params = dict(request.url.params) + assert params == {"my_query_param": "Foo"} + + # if both `query` and `extra_query` are given, they are merged + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + query={"bar": "1"}, + extra_query={"foo": "2"}, + ), + ), + ) + params = dict(request.url.params) + assert params == {"bar": "1", "foo": "2"} + + # `extra_query` takes priority over `query` when keys clash + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + query={"foo": "1"}, + extra_query={"foo": "2"}, + ), + ), + ) + params = dict(request.url.params) + assert params == {"foo": "2"} + + def test_multipart_repeating_array(self, client: Gcore) -> None: + request = client._build_request( + FinalRequestOptions.construct( + method="post", + url="/foo", + headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, + json_data={"array": ["foo", "bar"]}, + files=[("foo.txt", b"hello world")], + ) + ) + + assert request.read().split(b"\r\n") == [ + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="array[]"', + b"", + b"foo", + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="array[]"', + b"", + b"bar", + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="foo.txt"; filename="upload"', + b"Content-Type: application/octet-stream", + b"", + b"hello world", + b"--6b7ba517decee4a450543ea6ae821c82--", + b"", + ] + + @pytest.mark.respx(base_url=base_url) + def test_binary_content_upload(self, respx_mock: MockRouter, client: Gcore) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + response = client.post( + "/upload", + content=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + def test_binary_content_upload_with_iterator(self) -> None: + file_content = b"Hello, this is a test file." + counter = Counter() + iterator = _make_sync_iterator([file_content], counter=counter) + + def mock_handler(request: httpx.Request) -> httpx.Response: + assert counter.value == 0, "the request body should not have been read" + return httpx.Response(200, content=request.read()) + + with Gcore( + base_url=base_url, + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.Client(transport=MockTransport(handler=mock_handler)), + ) as client: + response = client.post( + "/upload", + content=iterator, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + assert counter.value == 1 + + @pytest.mark.respx(base_url=base_url) + def test_binary_content_upload_with_body_is_deprecated(self, respx_mock: MockRouter, client: Gcore) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + with pytest.deprecated_call( + match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead." + ): + response = client.post( + "/upload", + body=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + @pytest.mark.respx(base_url=base_url) + def test_basic_union_response(self, respx_mock: MockRouter, client: Gcore) -> None: + class Model1(BaseModel): + name: str + + class Model2(BaseModel): + foo: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + assert isinstance(response, Model2) + assert response.foo == "bar" + + @pytest.mark.respx(base_url=base_url) + def test_union_response_different_types(self, respx_mock: MockRouter, client: Gcore) -> None: + """Union of objects with the same field name using a different type""" + + class Model1(BaseModel): + foo: int + + class Model2(BaseModel): + foo: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + assert isinstance(response, Model2) + assert response.foo == "bar" + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) + + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + assert isinstance(response, Model1) + assert response.foo == 1 + + @pytest.mark.respx(base_url=base_url) + def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter, client: Gcore) -> None: + """ + Response that sets Content-Type to something other than application/json but returns json data + """ + + class Model(BaseModel): + foo: int + + respx_mock.get("/foo").mock( + return_value=httpx.Response( + 200, + content=json.dumps({"foo": 2}), + headers={"Content-Type": "application/text"}, + ) + ) + + response = client.get("/foo", cast_to=Model) + assert isinstance(response, Model) + assert response.foo == 2 + + def test_base_url_setter(self) -> None: + client = Gcore(base_url="https://example.com/from_init", api_key=api_key, _strict_response_validation=True) + assert client.base_url == "https://example.com/from_init/" + + client.base_url = "https://example.com/from_setter" # type: ignore[assignment] + + assert client.base_url == "https://example.com/from_setter/" + + client.close() + + def test_base_url_env(self) -> None: + with update_env(GCORE_BASE_URL="http://localhost:5000/from/env"): + client = Gcore(api_key=api_key, _strict_response_validation=True) + assert client.base_url == "http://localhost:5000/from/env/" + + @pytest.mark.parametrize( + "client", + [ + Gcore(base_url="http://localhost:5000/custom/path/", api_key=api_key, _strict_response_validation=True), + Gcore( + base_url="http://localhost:5000/custom/path/", + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.Client(), + ), + ], + ids=["standard", "custom http client"], + ) + def test_base_url_trailing_slash(self, client: Gcore) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar"}, + ), + ) + assert request.url == "http://localhost:5000/custom/path/foo" + client.close() + + @pytest.mark.parametrize( + "client", + [ + Gcore(base_url="http://localhost:5000/custom/path/", api_key=api_key, _strict_response_validation=True), + Gcore( + base_url="http://localhost:5000/custom/path/", + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.Client(), + ), + ], + ids=["standard", "custom http client"], + ) + def test_base_url_no_trailing_slash(self, client: Gcore) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar"}, + ), + ) + assert request.url == "http://localhost:5000/custom/path/foo" + client.close() + + @pytest.mark.parametrize( + "client", + [ + Gcore(base_url="http://localhost:5000/custom/path/", api_key=api_key, _strict_response_validation=True), + Gcore( + base_url="http://localhost:5000/custom/path/", + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.Client(), + ), + ], + ids=["standard", "custom http client"], + ) + def test_absolute_request_url(self, client: Gcore) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="https://myapi.com/foo", + json_data={"foo": "bar"}, + ), + ) + assert request.url == "https://myapi.com/foo" + client.close() + + def test_copied_client_does_not_close_http(self) -> None: + test_client = Gcore(base_url=base_url, api_key=api_key, _strict_response_validation=True) + assert not test_client.is_closed() + + copied = test_client.copy() + assert copied is not test_client + + del copied + + assert not test_client.is_closed() + + def test_client_context_manager(self) -> None: + test_client = Gcore(base_url=base_url, api_key=api_key, _strict_response_validation=True) + with test_client as c2: + assert c2 is test_client + assert not c2.is_closed() + assert not test_client.is_closed() + assert test_client.is_closed() + + @pytest.mark.respx(base_url=base_url) + def test_client_response_validation_error(self, respx_mock: MockRouter, client: Gcore) -> None: + class Model(BaseModel): + foo: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) + + with pytest.raises(APIResponseValidationError) as exc: + client.get("/foo", cast_to=Model) + + assert isinstance(exc.value.__cause__, ValidationError) + + def test_client_max_retries_validation(self) -> None: + with pytest.raises(TypeError, match=r"max_retries cannot be None"): + Gcore(base_url=base_url, api_key=api_key, _strict_response_validation=True, max_retries=cast(Any, None)) + + @pytest.mark.respx(base_url=base_url) + def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: + class Model(BaseModel): + name: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, text="my-custom-format")) + + strict_client = Gcore(base_url=base_url, api_key=api_key, _strict_response_validation=True) + + with pytest.raises(APIResponseValidationError): + strict_client.get("/foo", cast_to=Model) + + non_strict_client = Gcore(base_url=base_url, api_key=api_key, _strict_response_validation=False) + + response = non_strict_client.get("/foo", cast_to=Model) + assert isinstance(response, str) # type: ignore[unreachable] + + strict_client.close() + non_strict_client.close() + + @pytest.mark.parametrize( + "remaining_retries,retry_after,timeout", + [ + [3, "20", 20], + [3, "0", 0.5], + [3, "-10", 0.5], + [3, "60", 60], + [3, "61", 0.5], + [3, "Fri, 29 Sep 2023 16:26:57 GMT", 20], + [3, "Fri, 29 Sep 2023 16:26:37 GMT", 0.5], + [3, "Fri, 29 Sep 2023 16:26:27 GMT", 0.5], + [3, "Fri, 29 Sep 2023 16:27:37 GMT", 60], + [3, "Fri, 29 Sep 2023 16:27:38 GMT", 0.5], + [3, "99999999999999999999999999999999999", 0.5], + [3, "Zun, 29 Sep 2023 16:26:27 GMT", 0.5], + [3, "", 0.5], + [2, "", 0.5 * 2.0], + [1, "", 0.5 * 4.0], + [-1100, "", 8], # test large number potentially overflowing + ], + ) + @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) + def test_parse_retry_after_header( + self, remaining_retries: int, retry_after: str, timeout: float, client: Gcore + ) -> None: + headers = httpx.Headers({"retry-after": retry_after}) + options = FinalRequestOptions(method="get", url="/foo", max_retries=3) + calculated = client._calculate_retry_timeout(remaining_retries, options, headers) + assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] + + @mock.patch("gcore._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: Gcore) -> None: + respx_mock.post("/cloud/v1/projects").mock(side_effect=httpx.TimeoutException("Test timeout error")) + + with pytest.raises(APITimeoutError): + client.cloud.projects.with_streaming_response.create(name="my-project").__enter__() + + assert _get_open_connections(client) == 0 + + @mock.patch("gcore._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: Gcore) -> None: + respx_mock.post("/cloud/v1/projects").mock(return_value=httpx.Response(500)) + + with pytest.raises(APIStatusError): + client.cloud.projects.with_streaming_response.create(name="my-project").__enter__() + assert _get_open_connections(client) == 0 + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("gcore._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + @pytest.mark.parametrize("failure_mode", ["status", "exception"]) + def test_retries_taken( + self, + client: Gcore, + failures_before_success: int, + failure_mode: Literal["status", "exception"], + respx_mock: MockRouter, + ) -> None: + client = client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + if failure_mode == "exception": + raise RuntimeError("oops") + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/cloud/v1/projects").mock(side_effect=retry_handler) + + response = client.cloud.projects.with_raw_response.create(name="my-project") + + assert response.retries_taken == failures_before_success + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("gcore._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_omit_retry_count_header(self, client: Gcore, failures_before_success: int, respx_mock: MockRouter) -> None: + client = client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/cloud/v1/projects").mock(side_effect=retry_handler) + + response = client.cloud.projects.with_raw_response.create( + name="my-project", extra_headers={"x-stainless-retry-count": Omit()} + ) + + assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("gcore._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_overwrite_retry_count_header( + self, client: Gcore, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/cloud/v1/projects").mock(side_effect=retry_handler) + + response = client.cloud.projects.with_raw_response.create( + name="my-project", extra_headers={"x-stainless-retry-count": "42"} + ) + + assert response.http_request.headers.get("x-stainless-retry-count") == "42" + + def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: + # Test that the proxy environment variables are set correctly + monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + + client = DefaultHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + + @pytest.mark.respx(base_url=base_url) + def test_follow_redirects(self, respx_mock: MockRouter, client: Gcore) -> None: + # Test that the default follow_redirects=True allows following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) + + response = client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + + @pytest.mark.respx(base_url=base_url) + def test_follow_redirects_disabled(self, respx_mock: MockRouter, client: Gcore) -> None: + # Test that follow_redirects=False prevents following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + + with pytest.raises(APIStatusError) as exc_info: + client.post("/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response) + + assert exc_info.value.response.status_code == 302 + assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" + + +class TestAsyncGcore: + @pytest.mark.respx(base_url=base_url) + async def test_raw_response(self, respx_mock: MockRouter, async_client: AsyncGcore) -> None: + respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = await async_client.post("/foo", cast_to=httpx.Response) + assert response.status_code == 200 + assert isinstance(response, httpx.Response) + assert response.json() == {"foo": "bar"} + + @pytest.mark.respx(base_url=base_url) + async def test_raw_response_for_binary(self, respx_mock: MockRouter, async_client: AsyncGcore) -> None: + respx_mock.post("/foo").mock( + return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') + ) + + response = await async_client.post("/foo", cast_to=httpx.Response) + assert response.status_code == 200 + assert isinstance(response, httpx.Response) + assert response.json() == {"foo": "bar"} + + def test_copy(self, async_client: AsyncGcore) -> None: + copied = async_client.copy() + assert id(copied) != id(async_client) + + copied = async_client.copy(api_key="another My API Key") + assert copied.api_key == "another My API Key" + assert async_client.api_key == "My API Key" + + def test_copy_default_options(self, async_client: AsyncGcore) -> None: + # options that have a default are overridden correctly + copied = async_client.copy(max_retries=7) + assert copied.max_retries == 7 + assert async_client.max_retries == 2 + + copied2 = copied.copy(max_retries=6) + assert copied2.max_retries == 6 + assert copied.max_retries == 7 + + # timeout + assert isinstance(async_client.timeout, httpx.Timeout) + copied = async_client.copy(timeout=None) + assert copied.timeout is None + assert isinstance(async_client.timeout, httpx.Timeout) + + async def test_copy_default_headers(self) -> None: + client = AsyncGcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} + ) + assert client.default_headers["X-Foo"] == "bar" + + # does not override the already given value when not specified + copied = client.copy() + assert copied.default_headers["X-Foo"] == "bar" + + # merges already given headers + copied = client.copy(default_headers={"X-Bar": "stainless"}) + assert copied.default_headers["X-Foo"] == "bar" + assert copied.default_headers["X-Bar"] == "stainless" + + # uses new values for any already given headers + copied = client.copy(default_headers={"X-Foo": "stainless"}) + assert copied.default_headers["X-Foo"] == "stainless" + + # set_default_headers + + # completely overrides already set values + copied = client.copy(set_default_headers={}) + assert copied.default_headers.get("X-Foo") is None + + copied = client.copy(set_default_headers={"X-Bar": "Robert"}) + assert copied.default_headers["X-Bar"] == "Robert" + + with pytest.raises( + ValueError, + match="`default_headers` and `set_default_headers` arguments are mutually exclusive", + ): + client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + await client.close() + + async def test_copy_default_query(self) -> None: + client = AsyncGcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"foo": "bar"} + ) + assert _get_params(client)["foo"] == "bar" + + # does not override the already given value when not specified + copied = client.copy() + assert _get_params(copied)["foo"] == "bar" + + # merges already given params + copied = client.copy(default_query={"bar": "stainless"}) + params = _get_params(copied) + assert params["foo"] == "bar" + assert params["bar"] == "stainless" + + # uses new values for any already given headers + copied = client.copy(default_query={"foo": "stainless"}) + assert _get_params(copied)["foo"] == "stainless" + + # set_default_query + + # completely overrides already set values + copied = client.copy(set_default_query={}) + assert _get_params(copied) == {} + + copied = client.copy(set_default_query={"bar": "Robert"}) + assert _get_params(copied)["bar"] == "Robert" + + with pytest.raises( + ValueError, + # TODO: update + match="`default_query` and `set_default_query` arguments are mutually exclusive", + ): + client.copy(set_default_query={}, default_query={"foo": "Bar"}) + + await client.close() + + def test_copy_signature(self, async_client: AsyncGcore) -> None: + # ensure the same parameters that can be passed to the client are defined in the `.copy()` method + init_signature = inspect.signature( + # mypy doesn't like that we access the `__init__` property. + async_client.__init__, # type: ignore[misc] + ) + copy_signature = inspect.signature(async_client.copy) + exclude_params = {"transport", "proxies", "_strict_response_validation"} + + for name in init_signature.parameters.keys(): + if name in exclude_params: + continue + + copy_param = copy_signature.parameters.get(name) + assert copy_param is not None, f"copy() signature is missing the {name} param" + + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") + def test_copy_build_request(self, async_client: AsyncGcore) -> None: + options = FinalRequestOptions(method="get", url="/foo") + + def build_request(options: FinalRequestOptions) -> None: + client_copy = async_client.copy() + client_copy._build_request(options) + + # ensure that the machinery is warmed up before tracing starts. + build_request(options) + gc.collect() + + tracemalloc.start(1000) + + snapshot_before = tracemalloc.take_snapshot() + + ITERATIONS = 10 + for _ in range(ITERATIONS): + build_request(options) + + gc.collect() + snapshot_after = tracemalloc.take_snapshot() + + tracemalloc.stop() + + def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.StatisticDiff) -> None: + if diff.count == 0: + # Avoid false positives by considering only leaks (i.e. allocations that persist). + return + + if diff.count % ITERATIONS != 0: + # Avoid false positives by considering only leaks that appear per iteration. + return + + for frame in diff.traceback: + if any( + frame.filename.endswith(fragment) + for fragment in [ + # to_raw_response_wrapper leaks through the @functools.wraps() decorator. + # + # removing the decorator fixes the leak for reasons we don't understand. + "gcore/_legacy_response.py", + "gcore/_response.py", + # pydantic.BaseModel.model_dump || pydantic.BaseModel.dict leak memory for some reason. + "gcore/_compat.py", + # Standard library leaks we don't care about. + "/logging/__init__.py", + ] + ): + return + + leaks.append(diff) + + leaks: list[tracemalloc.StatisticDiff] = [] + for diff in snapshot_after.compare_to(snapshot_before, "traceback"): + add_leak(leaks, diff) + if leaks: + for leak in leaks: + print("MEMORY LEAK:", leak) + for frame in leak.traceback: + print(frame) + raise AssertionError() + + async def test_request_timeout(self, async_client: AsyncGcore) -> None: + request = async_client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == DEFAULT_TIMEOUT + + request = async_client._build_request( + FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) + ) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == httpx.Timeout(100.0) + + async def test_client_timeout_option(self) -> None: + client = AsyncGcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, timeout=httpx.Timeout(0) + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == httpx.Timeout(0) + + await client.close() + + async def test_http_client_timeout_option(self) -> None: + # custom timeout given to the httpx client should be used + async with httpx.AsyncClient(timeout=None) as http_client: + client = AsyncGcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == httpx.Timeout(None) + + await client.close() + + # no timeout given to the httpx client should not use the httpx default + async with httpx.AsyncClient() as http_client: + client = AsyncGcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == DEFAULT_TIMEOUT + + await client.close() + + # explicitly passing the default timeout currently results in it being ignored + async with httpx.AsyncClient(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: + client = AsyncGcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, http_client=http_client + ) + + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore + assert timeout == DEFAULT_TIMEOUT # our default + + await client.close() + + def test_invalid_http_client(self) -> None: + with pytest.raises(TypeError, match="Invalid `http_client` arg"): + with httpx.Client() as http_client: + AsyncGcore( + base_url=base_url, + api_key=api_key, + _strict_response_validation=True, + http_client=cast(Any, http_client), + ) + + async def test_default_headers_option(self) -> None: + test_client = AsyncGcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} + ) + request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("x-foo") == "bar" + assert request.headers.get("x-stainless-lang") == "python" + + test_client2 = AsyncGcore( + base_url=base_url, + api_key=api_key, + _strict_response_validation=True, + default_headers={ + "X-Foo": "stainless", + "X-Stainless-Lang": "my-overriding-header", + }, + ) + request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("x-foo") == "stainless" + assert request.headers.get("x-stainless-lang") == "my-overriding-header" + + await test_client.close() + await test_client2.close() + + def test_validate_headers(self) -> None: + client = AsyncGcore(base_url=base_url, api_key=api_key, _strict_response_validation=True) + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + assert request.headers.get("Authorization") == f"APIKey {api_key}" + + with pytest.raises(GcoreError): + with update_env(**{"GCORE_API_KEY": Omit()}): + client2 = AsyncGcore(base_url=base_url, api_key=None, _strict_response_validation=True) + _ = client2 + + async def test_default_query_option(self) -> None: + client = AsyncGcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} + ) + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + url = httpx.URL(request.url) + assert dict(url.params) == {"query_param": "bar"} + + request = client._build_request( + FinalRequestOptions( + method="get", + url="/foo", + params={"foo": "baz", "query_param": "overridden"}, + ) + ) + url = httpx.URL(request.url) + assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} + + await client.close() + + async def test_cloud_project_id_client_params(self, async_client: AsyncGcore) -> None: + # Test with base client (no custom params) + with pytest.raises(ValueError, match="Missing cloud_project_id argument;"): + await async_client.cloud.projects.update() + + client = AsyncGcore(base_url=base_url, api_key=api_key, _strict_response_validation=True, cloud_project_id=0) + async with client as c2: + await c2.cloud.projects.update() + + async def test_cloud_region_id_client_params(self, async_client: AsyncGcore) -> None: + # Test with base client (no custom params) + with pytest.raises(ValueError, match="Missing cloud_region_id argument;"): + await async_client.cloud.regions.get() + + client = AsyncGcore(base_url=base_url, api_key=api_key, _strict_response_validation=True, cloud_region_id=0) + async with client as c2: + await c2.cloud.regions.get() + + def test_request_extra_json(self, client: Gcore) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar"}, + extra_json={"baz": False}, + ), + ) + data = json.loads(request.content.decode("utf-8")) + assert data == {"foo": "bar", "baz": False} + + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + extra_json={"baz": False}, + ), + ) + data = json.loads(request.content.decode("utf-8")) + assert data == {"baz": False} + + # `extra_json` takes priority over `json_data` when keys clash + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar", "baz": True}, + extra_json={"baz": None}, + ), + ) + data = json.loads(request.content.decode("utf-8")) + assert data == {"foo": "bar", "baz": None} + + def test_request_extra_headers(self, client: Gcore) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options(extra_headers={"X-Foo": "Foo"}), + ), + ) + assert request.headers.get("X-Foo") == "Foo" + + # `extra_headers` takes priority over `default_headers` when keys clash + request = client.with_options(default_headers={"X-Bar": "true"})._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + extra_headers={"X-Bar": "false"}, + ), + ), + ) + assert request.headers.get("X-Bar") == "false" + + def test_request_extra_query(self, client: Gcore) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + extra_query={"my_query_param": "Foo"}, + ), + ), + ) + params = dict(request.url.params) + assert params == {"my_query_param": "Foo"} + + # if both `query` and `extra_query` are given, they are merged + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + query={"bar": "1"}, + extra_query={"foo": "2"}, + ), + ), + ) + params = dict(request.url.params) + assert params == {"bar": "1", "foo": "2"} + + # `extra_query` takes priority over `query` when keys clash + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + **make_request_options( + query={"foo": "1"}, + extra_query={"foo": "2"}, + ), + ), + ) + params = dict(request.url.params) + assert params == {"foo": "2"} + + def test_multipart_repeating_array(self, async_client: AsyncGcore) -> None: + request = async_client._build_request( + FinalRequestOptions.construct( + method="post", + url="/foo", + headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, + json_data={"array": ["foo", "bar"]}, + files=[("foo.txt", b"hello world")], + ) + ) + + assert request.read().split(b"\r\n") == [ + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="array[]"', + b"", + b"foo", + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="array[]"', + b"", + b"bar", + b"--6b7ba517decee4a450543ea6ae821c82", + b'Content-Disposition: form-data; name="foo.txt"; filename="upload"', + b"Content-Type: application/octet-stream", + b"", + b"hello world", + b"--6b7ba517decee4a450543ea6ae821c82--", + b"", + ] + + @pytest.mark.respx(base_url=base_url) + async def test_binary_content_upload(self, respx_mock: MockRouter, async_client: AsyncGcore) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + response = await async_client.post( + "/upload", + content=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + async def test_binary_content_upload_with_asynciterator(self) -> None: + file_content = b"Hello, this is a test file." + counter = Counter() + iterator = _make_async_iterator([file_content], counter=counter) + + async def mock_handler(request: httpx.Request) -> httpx.Response: + assert counter.value == 0, "the request body should not have been read" + return httpx.Response(200, content=await request.aread()) + + async with AsyncGcore( + base_url=base_url, + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.AsyncClient(transport=MockTransport(handler=mock_handler)), + ) as client: + response = await client.post( + "/upload", + content=iterator, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + assert counter.value == 1 + + @pytest.mark.respx(base_url=base_url) + async def test_binary_content_upload_with_body_is_deprecated( + self, respx_mock: MockRouter, async_client: AsyncGcore + ) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + with pytest.deprecated_call( + match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead." + ): + response = await async_client.post( + "/upload", + body=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + @pytest.mark.respx(base_url=base_url) + async def test_basic_union_response(self, respx_mock: MockRouter, async_client: AsyncGcore) -> None: + class Model1(BaseModel): + name: str + + class Model2(BaseModel): + foo: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + assert isinstance(response, Model2) + assert response.foo == "bar" + + @pytest.mark.respx(base_url=base_url) + async def test_union_response_different_types(self, respx_mock: MockRouter, async_client: AsyncGcore) -> None: + """Union of objects with the same field name using a different type""" + + class Model1(BaseModel): + foo: int + + class Model2(BaseModel): + foo: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + assert isinstance(response, Model2) + assert response.foo == "bar" + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) + + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + assert isinstance(response, Model1) + assert response.foo == 1 + + @pytest.mark.respx(base_url=base_url) + async def test_non_application_json_content_type_for_json_data( + self, respx_mock: MockRouter, async_client: AsyncGcore + ) -> None: + """ + Response that sets Content-Type to something other than application/json but returns json data + """ + + class Model(BaseModel): + foo: int + + respx_mock.get("/foo").mock( + return_value=httpx.Response( + 200, + content=json.dumps({"foo": 2}), + headers={"Content-Type": "application/text"}, + ) + ) + + response = await async_client.get("/foo", cast_to=Model) + assert isinstance(response, Model) + assert response.foo == 2 + + async def test_base_url_setter(self) -> None: + client = AsyncGcore(base_url="https://example.com/from_init", api_key=api_key, _strict_response_validation=True) + assert client.base_url == "https://example.com/from_init/" + + client.base_url = "https://example.com/from_setter" # type: ignore[assignment] + + assert client.base_url == "https://example.com/from_setter/" + + await client.close() + + async def test_base_url_env(self) -> None: + with update_env(GCORE_BASE_URL="http://localhost:5000/from/env"): + client = AsyncGcore(api_key=api_key, _strict_response_validation=True) + assert client.base_url == "http://localhost:5000/from/env/" + + @pytest.mark.parametrize( + "client", + [ + AsyncGcore( + base_url="http://localhost:5000/custom/path/", api_key=api_key, _strict_response_validation=True + ), + AsyncGcore( + base_url="http://localhost:5000/custom/path/", + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.AsyncClient(), + ), + ], + ids=["standard", "custom http client"], + ) + async def test_base_url_trailing_slash(self, client: AsyncGcore) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar"}, + ), + ) + assert request.url == "http://localhost:5000/custom/path/foo" + await client.close() + + @pytest.mark.parametrize( + "client", + [ + AsyncGcore( + base_url="http://localhost:5000/custom/path/", api_key=api_key, _strict_response_validation=True + ), + AsyncGcore( + base_url="http://localhost:5000/custom/path/", + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.AsyncClient(), + ), + ], + ids=["standard", "custom http client"], + ) + async def test_base_url_no_trailing_slash(self, client: AsyncGcore) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="/foo", + json_data={"foo": "bar"}, + ), + ) + assert request.url == "http://localhost:5000/custom/path/foo" + await client.close() + + @pytest.mark.parametrize( + "client", + [ + AsyncGcore( + base_url="http://localhost:5000/custom/path/", api_key=api_key, _strict_response_validation=True + ), + AsyncGcore( + base_url="http://localhost:5000/custom/path/", + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.AsyncClient(), + ), + ], + ids=["standard", "custom http client"], + ) + async def test_absolute_request_url(self, client: AsyncGcore) -> None: + request = client._build_request( + FinalRequestOptions( + method="post", + url="https://myapi.com/foo", + json_data={"foo": "bar"}, + ), + ) + assert request.url == "https://myapi.com/foo" + await client.close() + + async def test_copied_client_does_not_close_http(self) -> None: + test_client = AsyncGcore(base_url=base_url, api_key=api_key, _strict_response_validation=True) + assert not test_client.is_closed() + + copied = test_client.copy() + assert copied is not test_client + + del copied + + await asyncio.sleep(0.2) + assert not test_client.is_closed() + + async def test_client_context_manager(self) -> None: + test_client = AsyncGcore(base_url=base_url, api_key=api_key, _strict_response_validation=True) + async with test_client as c2: + assert c2 is test_client + assert not c2.is_closed() + assert not test_client.is_closed() + assert test_client.is_closed() + + @pytest.mark.respx(base_url=base_url) + async def test_client_response_validation_error(self, respx_mock: MockRouter, async_client: AsyncGcore) -> None: + class Model(BaseModel): + foo: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) + + with pytest.raises(APIResponseValidationError) as exc: + await async_client.get("/foo", cast_to=Model) + + assert isinstance(exc.value.__cause__, ValidationError) + + async def test_client_max_retries_validation(self) -> None: + with pytest.raises(TypeError, match=r"max_retries cannot be None"): + AsyncGcore( + base_url=base_url, api_key=api_key, _strict_response_validation=True, max_retries=cast(Any, None) + ) + + @pytest.mark.respx(base_url=base_url) + async def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: + class Model(BaseModel): + name: str + + respx_mock.get("/foo").mock(return_value=httpx.Response(200, text="my-custom-format")) + + strict_client = AsyncGcore(base_url=base_url, api_key=api_key, _strict_response_validation=True) + + with pytest.raises(APIResponseValidationError): + await strict_client.get("/foo", cast_to=Model) + + non_strict_client = AsyncGcore(base_url=base_url, api_key=api_key, _strict_response_validation=False) + + response = await non_strict_client.get("/foo", cast_to=Model) + assert isinstance(response, str) # type: ignore[unreachable] + + await strict_client.close() + await non_strict_client.close() + + @pytest.mark.parametrize( + "remaining_retries,retry_after,timeout", + [ + [3, "20", 20], + [3, "0", 0.5], + [3, "-10", 0.5], + [3, "60", 60], + [3, "61", 0.5], + [3, "Fri, 29 Sep 2023 16:26:57 GMT", 20], + [3, "Fri, 29 Sep 2023 16:26:37 GMT", 0.5], + [3, "Fri, 29 Sep 2023 16:26:27 GMT", 0.5], + [3, "Fri, 29 Sep 2023 16:27:37 GMT", 60], + [3, "Fri, 29 Sep 2023 16:27:38 GMT", 0.5], + [3, "99999999999999999999999999999999999", 0.5], + [3, "Zun, 29 Sep 2023 16:26:27 GMT", 0.5], + [3, "", 0.5], + [2, "", 0.5 * 2.0], + [1, "", 0.5 * 4.0], + [-1100, "", 8], # test large number potentially overflowing + ], + ) + @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) + async def test_parse_retry_after_header( + self, remaining_retries: int, retry_after: str, timeout: float, async_client: AsyncGcore + ) -> None: + headers = httpx.Headers({"retry-after": retry_after}) + options = FinalRequestOptions(method="get", url="/foo", max_retries=3) + calculated = async_client._calculate_retry_timeout(remaining_retries, options, headers) + assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] + + @mock.patch("gcore._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncGcore) -> None: + respx_mock.post("/cloud/v1/projects").mock(side_effect=httpx.TimeoutException("Test timeout error")) + + with pytest.raises(APITimeoutError): + await async_client.cloud.projects.with_streaming_response.create(name="my-project").__aenter__() + + assert _get_open_connections(async_client) == 0 + + @mock.patch("gcore._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncGcore) -> None: + respx_mock.post("/cloud/v1/projects").mock(return_value=httpx.Response(500)) + + with pytest.raises(APIStatusError): + await async_client.cloud.projects.with_streaming_response.create(name="my-project").__aenter__() + assert _get_open_connections(async_client) == 0 + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("gcore._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + @pytest.mark.parametrize("failure_mode", ["status", "exception"]) + async def test_retries_taken( + self, + async_client: AsyncGcore, + failures_before_success: int, + failure_mode: Literal["status", "exception"], + respx_mock: MockRouter, + ) -> None: + client = async_client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + if failure_mode == "exception": + raise RuntimeError("oops") + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/cloud/v1/projects").mock(side_effect=retry_handler) + + response = await client.cloud.projects.with_raw_response.create(name="my-project") + + assert response.retries_taken == failures_before_success + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("gcore._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + async def test_omit_retry_count_header( + self, async_client: AsyncGcore, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = async_client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/cloud/v1/projects").mock(side_effect=retry_handler) + + response = await client.cloud.projects.with_raw_response.create( + name="my-project", extra_headers={"x-stainless-retry-count": Omit()} + ) + + assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("gcore._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + async def test_overwrite_retry_count_header( + self, async_client: AsyncGcore, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = async_client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/cloud/v1/projects").mock(side_effect=retry_handler) + + response = await client.cloud.projects.with_raw_response.create( + name="my-project", extra_headers={"x-stainless-retry-count": "42"} + ) + + assert response.http_request.headers.get("x-stainless-retry-count") == "42" + + async def test_get_platform(self) -> None: + platform = await asyncify(get_platform)() + assert isinstance(platform, (str, OtherPlatform)) + + async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: + # Test that the proxy environment variables are set correctly + monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + + client = DefaultAsyncHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + async def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultAsyncHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + + @pytest.mark.respx(base_url=base_url) + async def test_follow_redirects(self, respx_mock: MockRouter, async_client: AsyncGcore) -> None: + # Test that the default follow_redirects=True allows following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) + + response = await async_client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + + @pytest.mark.respx(base_url=base_url) + async def test_follow_redirects_disabled(self, respx_mock: MockRouter, async_client: AsyncGcore) -> None: + # Test that follow_redirects=False prevents following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + + with pytest.raises(APIStatusError) as exc_info: + await async_client.post( + "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response + ) + + assert exc_info.value.response.status_code == 302 + assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" diff --git a/tests/test_deepcopy.py b/tests/test_deepcopy.py new file mode 100644 index 00000000..fe51174e --- /dev/null +++ b/tests/test_deepcopy.py @@ -0,0 +1,58 @@ +from gcore._utils import deepcopy_minimal + + +def assert_different_identities(obj1: object, obj2: object) -> None: + assert obj1 == obj2 + assert id(obj1) != id(obj2) + + +def test_simple_dict() -> None: + obj1 = {"foo": "bar"} + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + + +def test_nested_dict() -> None: + obj1 = {"foo": {"bar": True}} + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + assert_different_identities(obj1["foo"], obj2["foo"]) + + +def test_complex_nested_dict() -> None: + obj1 = {"foo": {"bar": [{"hello": "world"}]}} + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + assert_different_identities(obj1["foo"], obj2["foo"]) + assert_different_identities(obj1["foo"]["bar"], obj2["foo"]["bar"]) + assert_different_identities(obj1["foo"]["bar"][0], obj2["foo"]["bar"][0]) + + +def test_simple_list() -> None: + obj1 = ["a", "b", "c"] + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + + +def test_nested_list() -> None: + obj1 = ["a", [1, 2, 3]] + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + assert_different_identities(obj1[1], obj2[1]) + + +class MyObject: ... + + +def test_ignores_other_types() -> None: + # custom classes + my_obj = MyObject() + obj1 = {"foo": my_obj} + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + assert obj1["foo"] is my_obj + + # tuples + obj3 = ("a", "b") + obj4 = deepcopy_minimal(obj3) + assert obj3 is obj4 diff --git a/tests/test_extract_files.py b/tests/test_extract_files.py new file mode 100644 index 00000000..d67473bc --- /dev/null +++ b/tests/test_extract_files.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +from typing import Sequence + +import pytest + +from gcore._types import FileTypes +from gcore._utils import extract_files + + +def test_removes_files_from_input() -> None: + query = {"foo": "bar"} + assert extract_files(query, paths=[]) == [] + assert query == {"foo": "bar"} + + query2 = {"foo": b"Bar", "hello": "world"} + assert extract_files(query2, paths=[["foo"]]) == [("foo", b"Bar")] + assert query2 == {"hello": "world"} + + query3 = {"foo": {"foo": {"bar": b"Bar"}}, "hello": "world"} + assert extract_files(query3, paths=[["foo", "foo", "bar"]]) == [("foo[foo][bar]", b"Bar")] + assert query3 == {"foo": {"foo": {}}, "hello": "world"} + + query4 = {"foo": {"bar": b"Bar", "baz": "foo"}, "hello": "world"} + assert extract_files(query4, paths=[["foo", "bar"]]) == [("foo[bar]", b"Bar")] + assert query4 == {"hello": "world", "foo": {"baz": "foo"}} + + +def test_multiple_files() -> None: + query = {"documents": [{"file": b"My first file"}, {"file": b"My second file"}]} + assert extract_files(query, paths=[["documents", "", "file"]]) == [ + ("documents[][file]", b"My first file"), + ("documents[][file]", b"My second file"), + ] + assert query == {"documents": [{}, {}]} + + +@pytest.mark.parametrize( + "query,paths,expected", + [ + [ + {"foo": {"bar": "baz"}}, + [["foo", "", "bar"]], + [], + ], + [ + {"foo": ["bar", "baz"]}, + [["foo", "bar"]], + [], + ], + [ + {"foo": {"bar": "baz"}}, + [["foo", "foo"]], + [], + ], + ], + ids=["dict expecting array", "array expecting dict", "unknown keys"], +) +def test_ignores_incorrect_paths( + query: dict[str, object], + paths: Sequence[Sequence[str]], + expected: list[tuple[str, FileTypes]], +) -> None: + assert extract_files(query, paths=paths) == expected diff --git a/tests/test_files.py b/tests/test_files.py new file mode 100644 index 00000000..d8e5a6f7 --- /dev/null +++ b/tests/test_files.py @@ -0,0 +1,51 @@ +from pathlib import Path + +import anyio +import pytest +from dirty_equals import IsDict, IsList, IsBytes, IsTuple + +from gcore._files import to_httpx_files, async_to_httpx_files + +readme_path = Path(__file__).parent.parent.joinpath("README.md") + + +def test_pathlib_includes_file_name() -> None: + result = to_httpx_files({"file": readme_path}) + print(result) + assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) + + +def test_tuple_input() -> None: + result = to_httpx_files([("file", readme_path)]) + print(result) + assert result == IsList(IsTuple("file", IsTuple("README.md", IsBytes()))) + + +@pytest.mark.asyncio +async def test_async_pathlib_includes_file_name() -> None: + result = await async_to_httpx_files({"file": readme_path}) + print(result) + assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) + + +@pytest.mark.asyncio +async def test_async_supports_anyio_path() -> None: + result = await async_to_httpx_files({"file": anyio.Path(readme_path)}) + print(result) + assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) + + +@pytest.mark.asyncio +async def test_async_tuple_input() -> None: + result = await async_to_httpx_files([("file", readme_path)]) + print(result) + assert result == IsList(IsTuple("file", IsTuple("README.md", IsBytes()))) + + +def test_string_not_allowed() -> None: + with pytest.raises(TypeError, match="Expected file types input to be a FileContent type or to be a tuple"): + to_httpx_files( + { + "file": "foo", # type: ignore + } + ) diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 00000000..d899cd02 --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,963 @@ +import json +from typing import TYPE_CHECKING, Any, Dict, List, Union, Optional, cast +from datetime import datetime, timezone +from typing_extensions import Literal, Annotated, TypeAliasType + +import pytest +import pydantic +from pydantic import Field + +from gcore._utils import PropertyInfo +from gcore._compat import PYDANTIC_V1, parse_obj, model_dump, model_json +from gcore._models import DISCRIMINATOR_CACHE, BaseModel, construct_type + + +class BasicModel(BaseModel): + foo: str + + +@pytest.mark.parametrize("value", ["hello", 1], ids=["correct type", "mismatched"]) +def test_basic(value: object) -> None: + m = BasicModel.construct(foo=value) + assert m.foo == value + + +def test_directly_nested_model() -> None: + class NestedModel(BaseModel): + nested: BasicModel + + m = NestedModel.construct(nested={"foo": "Foo!"}) + assert m.nested.foo == "Foo!" + + # mismatched types + m = NestedModel.construct(nested="hello!") + assert cast(Any, m.nested) == "hello!" + + +def test_optional_nested_model() -> None: + class NestedModel(BaseModel): + nested: Optional[BasicModel] + + m1 = NestedModel.construct(nested=None) + assert m1.nested is None + + m2 = NestedModel.construct(nested={"foo": "bar"}) + assert m2.nested is not None + assert m2.nested.foo == "bar" + + # mismatched types + m3 = NestedModel.construct(nested={"foo"}) + assert isinstance(cast(Any, m3.nested), set) + assert cast(Any, m3.nested) == {"foo"} + + +def test_list_nested_model() -> None: + class NestedModel(BaseModel): + nested: List[BasicModel] + + m = NestedModel.construct(nested=[{"foo": "bar"}, {"foo": "2"}]) + assert m.nested is not None + assert isinstance(m.nested, list) + assert len(m.nested) == 2 + assert m.nested[0].foo == "bar" + assert m.nested[1].foo == "2" + + # mismatched types + m = NestedModel.construct(nested=True) + assert cast(Any, m.nested) is True + + m = NestedModel.construct(nested=[False]) + assert cast(Any, m.nested) == [False] + + +def test_optional_list_nested_model() -> None: + class NestedModel(BaseModel): + nested: Optional[List[BasicModel]] + + m1 = NestedModel.construct(nested=[{"foo": "bar"}, {"foo": "2"}]) + assert m1.nested is not None + assert isinstance(m1.nested, list) + assert len(m1.nested) == 2 + assert m1.nested[0].foo == "bar" + assert m1.nested[1].foo == "2" + + m2 = NestedModel.construct(nested=None) + assert m2.nested is None + + # mismatched types + m3 = NestedModel.construct(nested={1}) + assert cast(Any, m3.nested) == {1} + + m4 = NestedModel.construct(nested=[False]) + assert cast(Any, m4.nested) == [False] + + +def test_list_optional_items_nested_model() -> None: + class NestedModel(BaseModel): + nested: List[Optional[BasicModel]] + + m = NestedModel.construct(nested=[None, {"foo": "bar"}]) + assert m.nested is not None + assert isinstance(m.nested, list) + assert len(m.nested) == 2 + assert m.nested[0] is None + assert m.nested[1] is not None + assert m.nested[1].foo == "bar" + + # mismatched types + m3 = NestedModel.construct(nested="foo") + assert cast(Any, m3.nested) == "foo" + + m4 = NestedModel.construct(nested=[False]) + assert cast(Any, m4.nested) == [False] + + +def test_list_mismatched_type() -> None: + class NestedModel(BaseModel): + nested: List[str] + + m = NestedModel.construct(nested=False) + assert cast(Any, m.nested) is False + + +def test_raw_dictionary() -> None: + class NestedModel(BaseModel): + nested: Dict[str, str] + + m = NestedModel.construct(nested={"hello": "world"}) + assert m.nested == {"hello": "world"} + + # mismatched types + m = NestedModel.construct(nested=False) + assert cast(Any, m.nested) is False + + +def test_nested_dictionary_model() -> None: + class NestedModel(BaseModel): + nested: Dict[str, BasicModel] + + m = NestedModel.construct(nested={"hello": {"foo": "bar"}}) + assert isinstance(m.nested, dict) + assert m.nested["hello"].foo == "bar" + + # mismatched types + m = NestedModel.construct(nested={"hello": False}) + assert cast(Any, m.nested["hello"]) is False + + +def test_unknown_fields() -> None: + m1 = BasicModel.construct(foo="foo", unknown=1) + assert m1.foo == "foo" + assert cast(Any, m1).unknown == 1 + + m2 = BasicModel.construct(foo="foo", unknown={"foo_bar": True}) + assert m2.foo == "foo" + assert cast(Any, m2).unknown == {"foo_bar": True} + + assert model_dump(m2) == {"foo": "foo", "unknown": {"foo_bar": True}} + + +def test_strict_validation_unknown_fields() -> None: + class Model(BaseModel): + foo: str + + model = parse_obj(Model, dict(foo="hello!", user="Robert")) + assert model.foo == "hello!" + assert cast(Any, model).user == "Robert" + + assert model_dump(model) == {"foo": "hello!", "user": "Robert"} + + +def test_aliases() -> None: + class Model(BaseModel): + my_field: int = Field(alias="myField") + + m = Model.construct(myField=1) + assert m.my_field == 1 + + # mismatched types + m = Model.construct(myField={"hello": False}) + assert cast(Any, m.my_field) == {"hello": False} + + +def test_repr() -> None: + model = BasicModel(foo="bar") + assert str(model) == "BasicModel(foo='bar')" + assert repr(model) == "BasicModel(foo='bar')" + + +def test_repr_nested_model() -> None: + class Child(BaseModel): + name: str + age: int + + class Parent(BaseModel): + name: str + child: Child + + model = Parent(name="Robert", child=Child(name="Foo", age=5)) + assert str(model) == "Parent(name='Robert', child=Child(name='Foo', age=5))" + assert repr(model) == "Parent(name='Robert', child=Child(name='Foo', age=5))" + + +def test_optional_list() -> None: + class Submodel(BaseModel): + name: str + + class Model(BaseModel): + items: Optional[List[Submodel]] + + m = Model.construct(items=None) + assert m.items is None + + m = Model.construct(items=[]) + assert m.items == [] + + m = Model.construct(items=[{"name": "Robert"}]) + assert m.items is not None + assert len(m.items) == 1 + assert m.items[0].name == "Robert" + + +def test_nested_union_of_models() -> None: + class Submodel1(BaseModel): + bar: bool + + class Submodel2(BaseModel): + thing: str + + class Model(BaseModel): + foo: Union[Submodel1, Submodel2] + + m = Model.construct(foo={"thing": "hello"}) + assert isinstance(m.foo, Submodel2) + assert m.foo.thing == "hello" + + +def test_nested_union_of_mixed_types() -> None: + class Submodel1(BaseModel): + bar: bool + + class Model(BaseModel): + foo: Union[Submodel1, Literal[True], Literal["CARD_HOLDER"]] + + m = Model.construct(foo=True) + assert m.foo is True + + m = Model.construct(foo="CARD_HOLDER") + assert m.foo == "CARD_HOLDER" + + m = Model.construct(foo={"bar": False}) + assert isinstance(m.foo, Submodel1) + assert m.foo.bar is False + + +def test_nested_union_multiple_variants() -> None: + class Submodel1(BaseModel): + bar: bool + + class Submodel2(BaseModel): + thing: str + + class Submodel3(BaseModel): + foo: int + + class Model(BaseModel): + foo: Union[Submodel1, Submodel2, None, Submodel3] + + m = Model.construct(foo={"thing": "hello"}) + assert isinstance(m.foo, Submodel2) + assert m.foo.thing == "hello" + + m = Model.construct(foo=None) + assert m.foo is None + + m = Model.construct() + assert m.foo is None + + m = Model.construct(foo={"foo": "1"}) + assert isinstance(m.foo, Submodel3) + assert m.foo.foo == 1 + + +def test_nested_union_invalid_data() -> None: + class Submodel1(BaseModel): + level: int + + class Submodel2(BaseModel): + name: str + + class Model(BaseModel): + foo: Union[Submodel1, Submodel2] + + m = Model.construct(foo=True) + assert cast(bool, m.foo) is True + + m = Model.construct(foo={"name": 3}) + if PYDANTIC_V1: + assert isinstance(m.foo, Submodel2) + assert m.foo.name == "3" + else: + assert isinstance(m.foo, Submodel1) + assert m.foo.name == 3 # type: ignore + + +def test_list_of_unions() -> None: + class Submodel1(BaseModel): + level: int + + class Submodel2(BaseModel): + name: str + + class Model(BaseModel): + items: List[Union[Submodel1, Submodel2]] + + m = Model.construct(items=[{"level": 1}, {"name": "Robert"}]) + assert len(m.items) == 2 + assert isinstance(m.items[0], Submodel1) + assert m.items[0].level == 1 + assert isinstance(m.items[1], Submodel2) + assert m.items[1].name == "Robert" + + m = Model.construct(items=[{"level": -1}, 156]) + assert len(m.items) == 2 + assert isinstance(m.items[0], Submodel1) + assert m.items[0].level == -1 + assert cast(Any, m.items[1]) == 156 + + +def test_union_of_lists() -> None: + class SubModel1(BaseModel): + level: int + + class SubModel2(BaseModel): + name: str + + class Model(BaseModel): + items: Union[List[SubModel1], List[SubModel2]] + + # with one valid entry + m = Model.construct(items=[{"name": "Robert"}]) + assert len(m.items) == 1 + assert isinstance(m.items[0], SubModel2) + assert m.items[0].name == "Robert" + + # with two entries pointing to different types + m = Model.construct(items=[{"level": 1}, {"name": "Robert"}]) + assert len(m.items) == 2 + assert isinstance(m.items[0], SubModel1) + assert m.items[0].level == 1 + assert isinstance(m.items[1], SubModel1) + assert cast(Any, m.items[1]).name == "Robert" + + # with two entries pointing to *completely* different types + m = Model.construct(items=[{"level": -1}, 156]) + assert len(m.items) == 2 + assert isinstance(m.items[0], SubModel1) + assert m.items[0].level == -1 + assert cast(Any, m.items[1]) == 156 + + +def test_dict_of_union() -> None: + class SubModel1(BaseModel): + name: str + + class SubModel2(BaseModel): + foo: str + + class Model(BaseModel): + data: Dict[str, Union[SubModel1, SubModel2]] + + m = Model.construct(data={"hello": {"name": "there"}, "foo": {"foo": "bar"}}) + assert len(list(m.data.keys())) == 2 + assert isinstance(m.data["hello"], SubModel1) + assert m.data["hello"].name == "there" + assert isinstance(m.data["foo"], SubModel2) + assert m.data["foo"].foo == "bar" + + # TODO: test mismatched type + + +def test_double_nested_union() -> None: + class SubModel1(BaseModel): + name: str + + class SubModel2(BaseModel): + bar: str + + class Model(BaseModel): + data: Dict[str, List[Union[SubModel1, SubModel2]]] + + m = Model.construct(data={"foo": [{"bar": "baz"}, {"name": "Robert"}]}) + assert len(m.data["foo"]) == 2 + + entry1 = m.data["foo"][0] + assert isinstance(entry1, SubModel2) + assert entry1.bar == "baz" + + entry2 = m.data["foo"][1] + assert isinstance(entry2, SubModel1) + assert entry2.name == "Robert" + + # TODO: test mismatched type + + +def test_union_of_dict() -> None: + class SubModel1(BaseModel): + name: str + + class SubModel2(BaseModel): + foo: str + + class Model(BaseModel): + data: Union[Dict[str, SubModel1], Dict[str, SubModel2]] + + m = Model.construct(data={"hello": {"name": "there"}, "foo": {"foo": "bar"}}) + assert len(list(m.data.keys())) == 2 + assert isinstance(m.data["hello"], SubModel1) + assert m.data["hello"].name == "there" + assert isinstance(m.data["foo"], SubModel1) + assert cast(Any, m.data["foo"]).foo == "bar" + + +def test_iso8601_datetime() -> None: + class Model(BaseModel): + created_at: datetime + + expected = datetime(2019, 12, 27, 18, 11, 19, 117000, tzinfo=timezone.utc) + + if PYDANTIC_V1: + expected_json = '{"created_at": "2019-12-27T18:11:19.117000+00:00"}' + else: + expected_json = '{"created_at":"2019-12-27T18:11:19.117000Z"}' + + model = Model.construct(created_at="2019-12-27T18:11:19.117Z") + assert model.created_at == expected + assert model_json(model) == expected_json + + model = parse_obj(Model, dict(created_at="2019-12-27T18:11:19.117Z")) + assert model.created_at == expected + assert model_json(model) == expected_json + + +def test_does_not_coerce_int() -> None: + class Model(BaseModel): + bar: int + + assert Model.construct(bar=1).bar == 1 + assert Model.construct(bar=10.9).bar == 10.9 + assert Model.construct(bar="19").bar == "19" # type: ignore[comparison-overlap] + assert Model.construct(bar=False).bar is False + + +def test_int_to_float_safe_conversion() -> None: + class Model(BaseModel): + float_field: float + + m = Model.construct(float_field=10) + assert m.float_field == 10.0 + assert isinstance(m.float_field, float) + + m = Model.construct(float_field=10.12) + assert m.float_field == 10.12 + assert isinstance(m.float_field, float) + + # number too big + m = Model.construct(float_field=2**53 + 1) + assert m.float_field == 2**53 + 1 + assert isinstance(m.float_field, int) + + +def test_deprecated_alias() -> None: + class Model(BaseModel): + resource_id: str = Field(alias="model_id") + + @property + def model_id(self) -> str: + return self.resource_id + + m = Model.construct(model_id="id") + assert m.model_id == "id" + assert m.resource_id == "id" + assert m.resource_id is m.model_id + + m = parse_obj(Model, {"model_id": "id"}) + assert m.model_id == "id" + assert m.resource_id == "id" + assert m.resource_id is m.model_id + + +def test_omitted_fields() -> None: + class Model(BaseModel): + resource_id: Optional[str] = None + + m = Model.construct() + assert m.resource_id is None + assert "resource_id" not in m.model_fields_set + + m = Model.construct(resource_id=None) + assert m.resource_id is None + assert "resource_id" in m.model_fields_set + + m = Model.construct(resource_id="foo") + assert m.resource_id == "foo" + assert "resource_id" in m.model_fields_set + + +def test_to_dict() -> None: + class Model(BaseModel): + foo: Optional[str] = Field(alias="FOO", default=None) + + m = Model(FOO="hello") + assert m.to_dict() == {"FOO": "hello"} + assert m.to_dict(use_api_names=False) == {"foo": "hello"} + + m2 = Model() + assert m2.to_dict() == {} + assert m2.to_dict(exclude_unset=False) == {"FOO": None} + assert m2.to_dict(exclude_unset=False, exclude_none=True) == {} + assert m2.to_dict(exclude_unset=False, exclude_defaults=True) == {} + + m3 = Model(FOO=None) + assert m3.to_dict() == {"FOO": None} + assert m3.to_dict(exclude_none=True) == {} + assert m3.to_dict(exclude_defaults=True) == {} + + class Model2(BaseModel): + created_at: datetime + + time_str = "2024-03-21T11:39:01.275859" + m4 = Model2.construct(created_at=time_str) + assert m4.to_dict(mode="python") == {"created_at": datetime.fromisoformat(time_str)} + assert m4.to_dict(mode="json") == {"created_at": time_str} + + if PYDANTIC_V1: + with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): + m.to_dict(warnings=False) + + +def test_forwards_compat_model_dump_method() -> None: + class Model(BaseModel): + foo: Optional[str] = Field(alias="FOO", default=None) + + m = Model(FOO="hello") + assert m.model_dump() == {"foo": "hello"} + assert m.model_dump(include={"bar"}) == {} + assert m.model_dump(exclude={"foo"}) == {} + assert m.model_dump(by_alias=True) == {"FOO": "hello"} + + m2 = Model() + assert m2.model_dump() == {"foo": None} + assert m2.model_dump(exclude_unset=True) == {} + assert m2.model_dump(exclude_none=True) == {} + assert m2.model_dump(exclude_defaults=True) == {} + + m3 = Model(FOO=None) + assert m3.model_dump() == {"foo": None} + assert m3.model_dump(exclude_none=True) == {} + + if PYDANTIC_V1: + with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): + m.model_dump(round_trip=True) + + with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): + m.model_dump(warnings=False) + + +def test_compat_method_no_error_for_warnings() -> None: + class Model(BaseModel): + foo: Optional[str] + + m = Model(foo="hello") + assert isinstance(model_dump(m, warnings=False), dict) + + +def test_to_json() -> None: + class Model(BaseModel): + foo: Optional[str] = Field(alias="FOO", default=None) + + m = Model(FOO="hello") + assert json.loads(m.to_json()) == {"FOO": "hello"} + assert json.loads(m.to_json(use_api_names=False)) == {"foo": "hello"} + + if PYDANTIC_V1: + assert m.to_json(indent=None) == '{"FOO": "hello"}' + else: + assert m.to_json(indent=None) == '{"FOO":"hello"}' + + m2 = Model() + assert json.loads(m2.to_json()) == {} + assert json.loads(m2.to_json(exclude_unset=False)) == {"FOO": None} + assert json.loads(m2.to_json(exclude_unset=False, exclude_none=True)) == {} + assert json.loads(m2.to_json(exclude_unset=False, exclude_defaults=True)) == {} + + m3 = Model(FOO=None) + assert json.loads(m3.to_json()) == {"FOO": None} + assert json.loads(m3.to_json(exclude_none=True)) == {} + + if PYDANTIC_V1: + with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): + m.to_json(warnings=False) + + +def test_forwards_compat_model_dump_json_method() -> None: + class Model(BaseModel): + foo: Optional[str] = Field(alias="FOO", default=None) + + m = Model(FOO="hello") + assert json.loads(m.model_dump_json()) == {"foo": "hello"} + assert json.loads(m.model_dump_json(include={"bar"})) == {} + assert json.loads(m.model_dump_json(include={"foo"})) == {"foo": "hello"} + assert json.loads(m.model_dump_json(by_alias=True)) == {"FOO": "hello"} + + assert m.model_dump_json(indent=2) == '{\n "foo": "hello"\n}' + + m2 = Model() + assert json.loads(m2.model_dump_json()) == {"foo": None} + assert json.loads(m2.model_dump_json(exclude_unset=True)) == {} + assert json.loads(m2.model_dump_json(exclude_none=True)) == {} + assert json.loads(m2.model_dump_json(exclude_defaults=True)) == {} + + m3 = Model(FOO=None) + assert json.loads(m3.model_dump_json()) == {"foo": None} + assert json.loads(m3.model_dump_json(exclude_none=True)) == {} + + if PYDANTIC_V1: + with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): + m.model_dump_json(round_trip=True) + + with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): + m.model_dump_json(warnings=False) + + +def test_type_compat() -> None: + # our model type can be assigned to Pydantic's model type + + def takes_pydantic(model: pydantic.BaseModel) -> None: # noqa: ARG001 + ... + + class OurModel(BaseModel): + foo: Optional[str] = None + + takes_pydantic(OurModel()) + + +def test_annotated_types() -> None: + class Model(BaseModel): + value: str + + m = construct_type( + value={"value": "foo"}, + type_=cast(Any, Annotated[Model, "random metadata"]), + ) + assert isinstance(m, Model) + assert m.value == "foo" + + +def test_discriminated_unions_invalid_data() -> None: + class A(BaseModel): + type: Literal["a"] + + data: str + + class B(BaseModel): + type: Literal["b"] + + data: int + + m = construct_type( + value={"type": "b", "data": "foo"}, + type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="type")]), + ) + assert isinstance(m, B) + assert m.type == "b" + assert m.data == "foo" # type: ignore[comparison-overlap] + + m = construct_type( + value={"type": "a", "data": 100}, + type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="type")]), + ) + assert isinstance(m, A) + assert m.type == "a" + if PYDANTIC_V1: + # pydantic v1 automatically converts inputs to strings + # if the expected type is a str + assert m.data == "100" + else: + assert m.data == 100 # type: ignore[comparison-overlap] + + +def test_discriminated_unions_unknown_variant() -> None: + class A(BaseModel): + type: Literal["a"] + + data: str + + class B(BaseModel): + type: Literal["b"] + + data: int + + m = construct_type( + value={"type": "c", "data": None, "new_thing": "bar"}, + type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="type")]), + ) + + # just chooses the first variant + assert isinstance(m, A) + assert m.type == "c" # type: ignore[comparison-overlap] + assert m.data == None # type: ignore[unreachable] + assert m.new_thing == "bar" + + +def test_discriminated_unions_invalid_data_nested_unions() -> None: + class A(BaseModel): + type: Literal["a"] + + data: str + + class B(BaseModel): + type: Literal["b"] + + data: int + + class C(BaseModel): + type: Literal["c"] + + data: bool + + m = construct_type( + value={"type": "b", "data": "foo"}, + type_=cast(Any, Annotated[Union[Union[A, B], C], PropertyInfo(discriminator="type")]), + ) + assert isinstance(m, B) + assert m.type == "b" + assert m.data == "foo" # type: ignore[comparison-overlap] + + m = construct_type( + value={"type": "c", "data": "foo"}, + type_=cast(Any, Annotated[Union[Union[A, B], C], PropertyInfo(discriminator="type")]), + ) + assert isinstance(m, C) + assert m.type == "c" + assert m.data == "foo" # type: ignore[comparison-overlap] + + +def test_discriminated_unions_with_aliases_invalid_data() -> None: + class A(BaseModel): + foo_type: Literal["a"] = Field(alias="type") + + data: str + + class B(BaseModel): + foo_type: Literal["b"] = Field(alias="type") + + data: int + + m = construct_type( + value={"type": "b", "data": "foo"}, + type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="foo_type")]), + ) + assert isinstance(m, B) + assert m.foo_type == "b" + assert m.data == "foo" # type: ignore[comparison-overlap] + + m = construct_type( + value={"type": "a", "data": 100}, + type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="foo_type")]), + ) + assert isinstance(m, A) + assert m.foo_type == "a" + if PYDANTIC_V1: + # pydantic v1 automatically converts inputs to strings + # if the expected type is a str + assert m.data == "100" + else: + assert m.data == 100 # type: ignore[comparison-overlap] + + +def test_discriminated_unions_overlapping_discriminators_invalid_data() -> None: + class A(BaseModel): + type: Literal["a"] + + data: bool + + class B(BaseModel): + type: Literal["a"] + + data: int + + m = construct_type( + value={"type": "a", "data": "foo"}, + type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="type")]), + ) + assert isinstance(m, B) + assert m.type == "a" + assert m.data == "foo" # type: ignore[comparison-overlap] + + +def test_discriminated_unions_invalid_data_uses_cache() -> None: + class A(BaseModel): + type: Literal["a"] + + data: str + + class B(BaseModel): + type: Literal["b"] + + data: int + + UnionType = cast(Any, Union[A, B]) + + assert not DISCRIMINATOR_CACHE.get(UnionType) + + m = construct_type( + value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")]) + ) + assert isinstance(m, B) + assert m.type == "b" + assert m.data == "foo" # type: ignore[comparison-overlap] + + discriminator = DISCRIMINATOR_CACHE.get(UnionType) + assert discriminator is not None + + m = construct_type( + value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")]) + ) + assert isinstance(m, B) + assert m.type == "b" + assert m.data == "foo" # type: ignore[comparison-overlap] + + # if the discriminator details object stays the same between invocations then + # we hit the cache + assert DISCRIMINATOR_CACHE.get(UnionType) is discriminator + + +@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") +def test_type_alias_type() -> None: + Alias = TypeAliasType("Alias", str) # pyright: ignore + + class Model(BaseModel): + alias: Alias + union: Union[int, Alias] + + m = construct_type(value={"alias": "foo", "union": "bar"}, type_=Model) + assert isinstance(m, Model) + assert isinstance(m.alias, str) + assert m.alias == "foo" + assert isinstance(m.union, str) + assert m.union == "bar" + + +@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") +def test_field_named_cls() -> None: + class Model(BaseModel): + cls: str + + m = construct_type(value={"cls": "foo"}, type_=Model) + assert isinstance(m, Model) + assert isinstance(m.cls, str) + + +def test_discriminated_union_case() -> None: + class A(BaseModel): + type: Literal["a"] + + data: bool + + class B(BaseModel): + type: Literal["b"] + + data: List[Union[A, object]] + + class ModelA(BaseModel): + type: Literal["modelA"] + + data: int + + class ModelB(BaseModel): + type: Literal["modelB"] + + required: str + + data: Union[A, B] + + # when constructing ModelA | ModelB, value data doesn't match ModelB exactly - missing `required` + m = construct_type( + value={"type": "modelB", "data": {"type": "a", "data": True}}, + type_=cast(Any, Annotated[Union[ModelA, ModelB], PropertyInfo(discriminator="type")]), + ) + + assert isinstance(m, ModelB) + + +def test_nested_discriminated_union() -> None: + class InnerType1(BaseModel): + type: Literal["type_1"] + + class InnerModel(BaseModel): + inner_value: str + + class InnerType2(BaseModel): + type: Literal["type_2"] + some_inner_model: InnerModel + + class Type1(BaseModel): + base_type: Literal["base_type_1"] + value: Annotated[ + Union[ + InnerType1, + InnerType2, + ], + PropertyInfo(discriminator="type"), + ] + + class Type2(BaseModel): + base_type: Literal["base_type_2"] + + T = Annotated[ + Union[ + Type1, + Type2, + ], + PropertyInfo(discriminator="base_type"), + ] + + model = construct_type( + type_=T, + value={ + "base_type": "base_type_1", + "value": { + "type": "type_2", + }, + }, + ) + assert isinstance(model, Type1) + assert isinstance(model.value, InnerType2) + + +@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2 for now") +def test_extra_properties() -> None: + class Item(BaseModel): + prop: int + + class Model(BaseModel): + __pydantic_extra__: Dict[str, Item] = Field(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + + other: str + + if TYPE_CHECKING: + + def __getattr__(self, attr: str) -> Item: ... + + model = construct_type( + type_=Model, + value={ + "a": {"prop": 1}, + "other": "foo", + }, + ) + assert isinstance(model, Model) + assert model.a.prop == 1 + assert isinstance(model.a, Item) + assert model.other == "foo" diff --git a/tests/test_qs.py b/tests/test_qs.py new file mode 100644 index 00000000..bdf9aa76 --- /dev/null +++ b/tests/test_qs.py @@ -0,0 +1,78 @@ +from typing import Any, cast +from functools import partial +from urllib.parse import unquote + +import pytest + +from gcore._qs import Querystring, stringify + + +def test_empty() -> None: + assert stringify({}) == "" + assert stringify({"a": {}}) == "" + assert stringify({"a": {"b": {"c": {}}}}) == "" + + +def test_basic() -> None: + assert stringify({"a": 1}) == "a=1" + assert stringify({"a": "b"}) == "a=b" + assert stringify({"a": True}) == "a=true" + assert stringify({"a": False}) == "a=false" + assert stringify({"a": 1.23456}) == "a=1.23456" + assert stringify({"a": None}) == "" + + +@pytest.mark.parametrize("method", ["class", "function"]) +def test_nested_dotted(method: str) -> None: + if method == "class": + serialise = Querystring(nested_format="dots").stringify + else: + serialise = partial(stringify, nested_format="dots") + + assert unquote(serialise({"a": {"b": "c"}})) == "a.b=c" + assert unquote(serialise({"a": {"b": "c", "d": "e", "f": "g"}})) == "a.b=c&a.d=e&a.f=g" + assert unquote(serialise({"a": {"b": {"c": {"d": "e"}}}})) == "a.b.c.d=e" + assert unquote(serialise({"a": {"b": True}})) == "a.b=true" + + +def test_nested_brackets() -> None: + assert unquote(stringify({"a": {"b": "c"}})) == "a[b]=c" + assert unquote(stringify({"a": {"b": "c", "d": "e", "f": "g"}})) == "a[b]=c&a[d]=e&a[f]=g" + assert unquote(stringify({"a": {"b": {"c": {"d": "e"}}}})) == "a[b][c][d]=e" + assert unquote(stringify({"a": {"b": True}})) == "a[b]=true" + + +@pytest.mark.parametrize("method", ["class", "function"]) +def test_array_comma(method: str) -> None: + if method == "class": + serialise = Querystring(array_format="comma").stringify + else: + serialise = partial(stringify, array_format="comma") + + assert unquote(serialise({"in": ["foo", "bar"]})) == "in=foo,bar" + assert unquote(serialise({"a": {"b": [True, False]}})) == "a[b]=true,false" + assert unquote(serialise({"a": {"b": [True, False, None, True]}})) == "a[b]=true,false,true" + + +def test_array_repeat() -> None: + assert unquote(stringify({"in": ["foo", "bar"]})) == "in=foo&in=bar" + assert unquote(stringify({"a": {"b": [True, False]}})) == "a[b]=true&a[b]=false" + assert unquote(stringify({"a": {"b": [True, False, None, True]}})) == "a[b]=true&a[b]=false&a[b]=true" + assert unquote(stringify({"in": ["foo", {"b": {"c": ["d", "e"]}}]})) == "in=foo&in[b][c]=d&in[b][c]=e" + + +@pytest.mark.parametrize("method", ["class", "function"]) +def test_array_brackets(method: str) -> None: + if method == "class": + serialise = Querystring(array_format="brackets").stringify + else: + serialise = partial(stringify, array_format="brackets") + + assert unquote(serialise({"in": ["foo", "bar"]})) == "in[]=foo&in[]=bar" + assert unquote(serialise({"a": {"b": [True, False]}})) == "a[b][]=true&a[b][]=false" + assert unquote(serialise({"a": {"b": [True, False, None, True]}})) == "a[b][]=true&a[b][]=false&a[b][]=true" + + +def test_unknown_array_format() -> None: + with pytest.raises(NotImplementedError, match="Unknown array_format value: foo, choose from comma, repeat"): + stringify({"a": ["foo", "bar"]}, array_format=cast(Any, "foo")) diff --git a/tests/test_required_args.py b/tests/test_required_args.py new file mode 100644 index 00000000..3e6908fb --- /dev/null +++ b/tests/test_required_args.py @@ -0,0 +1,111 @@ +from __future__ import annotations + +import pytest + +from gcore._utils import required_args + + +def test_too_many_positional_params() -> None: + @required_args(["a"]) + def foo(a: str | None = None) -> str | None: + return a + + with pytest.raises(TypeError, match=r"foo\(\) takes 1 argument\(s\) but 2 were given"): + foo("a", "b") # type: ignore + + +def test_positional_param() -> None: + @required_args(["a"]) + def foo(a: str | None = None) -> str | None: + return a + + assert foo("a") == "a" + assert foo(None) is None + assert foo(a="b") == "b" + + with pytest.raises(TypeError, match="Missing required argument: 'a'"): + foo() + + +def test_keyword_only_param() -> None: + @required_args(["a"]) + def foo(*, a: str | None = None) -> str | None: + return a + + assert foo(a="a") == "a" + assert foo(a=None) is None + assert foo(a="b") == "b" + + with pytest.raises(TypeError, match="Missing required argument: 'a'"): + foo() + + +def test_multiple_params() -> None: + @required_args(["a", "b", "c"]) + def foo(a: str = "", *, b: str = "", c: str = "") -> str | None: + return f"{a} {b} {c}" + + assert foo(a="a", b="b", c="c") == "a b c" + + error_message = r"Missing required arguments.*" + + with pytest.raises(TypeError, match=error_message): + foo() + + with pytest.raises(TypeError, match=error_message): + foo(a="a") + + with pytest.raises(TypeError, match=error_message): + foo(b="b") + + with pytest.raises(TypeError, match=error_message): + foo(c="c") + + with pytest.raises(TypeError, match=r"Missing required argument: 'a'"): + foo(b="a", c="c") + + with pytest.raises(TypeError, match=r"Missing required argument: 'b'"): + foo("a", c="c") + + +def test_multiple_variants() -> None: + @required_args(["a"], ["b"]) + def foo(*, a: str | None = None, b: str | None = None) -> str | None: + return a if a is not None else b + + assert foo(a="foo") == "foo" + assert foo(b="bar") == "bar" + assert foo(a=None) is None + assert foo(b=None) is None + + # TODO: this error message could probably be improved + with pytest.raises( + TypeError, + match=r"Missing required arguments; Expected either \('a'\) or \('b'\) arguments to be given", + ): + foo() + + +def test_multiple_params_multiple_variants() -> None: + @required_args(["a", "b"], ["c"]) + def foo(*, a: str | None = None, b: str | None = None, c: str | None = None) -> str | None: + if a is not None: + return a + if b is not None: + return b + return c + + error_message = r"Missing required arguments; Expected either \('a' and 'b'\) or \('c'\) arguments to be given" + + with pytest.raises(TypeError, match=error_message): + foo(a="foo") + + with pytest.raises(TypeError, match=error_message): + foo(b="bar") + + with pytest.raises(TypeError, match=error_message): + foo() + + assert foo(a=None, b="bar") == "bar" + assert foo(c=None) is None + assert foo(c="foo") == "foo" diff --git a/tests/test_response.py b/tests/test_response.py new file mode 100644 index 00000000..adec42e5 --- /dev/null +++ b/tests/test_response.py @@ -0,0 +1,277 @@ +import json +from typing import Any, List, Union, cast +from typing_extensions import Annotated + +import httpx +import pytest +import pydantic + +from gcore import Gcore, BaseModel, AsyncGcore +from gcore._response import ( + APIResponse, + BaseAPIResponse, + AsyncAPIResponse, + BinaryAPIResponse, + AsyncBinaryAPIResponse, + extract_response_type, +) +from gcore._streaming import Stream +from gcore._base_client import FinalRequestOptions + + +class ConcreteBaseAPIResponse(APIResponse[bytes]): ... + + +class ConcreteAPIResponse(APIResponse[List[str]]): ... + + +class ConcreteAsyncAPIResponse(APIResponse[httpx.Response]): ... + + +def test_extract_response_type_direct_classes() -> None: + assert extract_response_type(BaseAPIResponse[str]) == str + assert extract_response_type(APIResponse[str]) == str + assert extract_response_type(AsyncAPIResponse[str]) == str + + +def test_extract_response_type_direct_class_missing_type_arg() -> None: + with pytest.raises( + RuntimeError, + match="Expected type to have a type argument at index 0 but it did not", + ): + extract_response_type(AsyncAPIResponse) + + +def test_extract_response_type_concrete_subclasses() -> None: + assert extract_response_type(ConcreteBaseAPIResponse) == bytes + assert extract_response_type(ConcreteAPIResponse) == List[str] + assert extract_response_type(ConcreteAsyncAPIResponse) == httpx.Response + + +def test_extract_response_type_binary_response() -> None: + assert extract_response_type(BinaryAPIResponse) == bytes + assert extract_response_type(AsyncBinaryAPIResponse) == bytes + + +class PydanticModel(pydantic.BaseModel): ... + + +def test_response_parse_mismatched_basemodel(client: Gcore) -> None: + response = APIResponse( + raw=httpx.Response(200, content=b"foo"), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + with pytest.raises( + TypeError, + match="Pydantic models must subclass our base model type, e.g. `from gcore import BaseModel`", + ): + response.parse(to=PydanticModel) + + +@pytest.mark.asyncio +async def test_async_response_parse_mismatched_basemodel(async_client: AsyncGcore) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=b"foo"), + client=async_client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + with pytest.raises( + TypeError, + match="Pydantic models must subclass our base model type, e.g. `from gcore import BaseModel`", + ): + await response.parse(to=PydanticModel) + + +def test_response_parse_custom_stream(client: Gcore) -> None: + response = APIResponse( + raw=httpx.Response(200, content=b"foo"), + client=client, + stream=True, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + stream = response.parse(to=Stream[int]) + assert stream._cast_to == int + + +@pytest.mark.asyncio +async def test_async_response_parse_custom_stream(async_client: AsyncGcore) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=b"foo"), + client=async_client, + stream=True, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + stream = await response.parse(to=Stream[int]) + assert stream._cast_to == int + + +class CustomModel(BaseModel): + foo: str + bar: int + + +def test_response_parse_custom_model(client: Gcore) -> None: + response = APIResponse( + raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = response.parse(to=CustomModel) + assert obj.foo == "hello!" + assert obj.bar == 2 + + +@pytest.mark.asyncio +async def test_async_response_parse_custom_model(async_client: AsyncGcore) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), + client=async_client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = await response.parse(to=CustomModel) + assert obj.foo == "hello!" + assert obj.bar == 2 + + +def test_response_parse_annotated_type(client: Gcore) -> None: + response = APIResponse( + raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = response.parse( + to=cast("type[CustomModel]", Annotated[CustomModel, "random metadata"]), + ) + assert obj.foo == "hello!" + assert obj.bar == 2 + + +async def test_async_response_parse_annotated_type(async_client: AsyncGcore) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), + client=async_client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = await response.parse( + to=cast("type[CustomModel]", Annotated[CustomModel, "random metadata"]), + ) + assert obj.foo == "hello!" + assert obj.bar == 2 + + +@pytest.mark.parametrize( + "content, expected", + [ + ("false", False), + ("true", True), + ("False", False), + ("True", True), + ("TrUe", True), + ("FalSe", False), + ], +) +def test_response_parse_bool(client: Gcore, content: str, expected: bool) -> None: + response = APIResponse( + raw=httpx.Response(200, content=content), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + result = response.parse(to=bool) + assert result is expected + + +@pytest.mark.parametrize( + "content, expected", + [ + ("false", False), + ("true", True), + ("False", False), + ("True", True), + ("TrUe", True), + ("FalSe", False), + ], +) +async def test_async_response_parse_bool(client: AsyncGcore, content: str, expected: bool) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=content), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + result = await response.parse(to=bool) + assert result is expected + + +class OtherModel(BaseModel): + a: str + + +@pytest.mark.parametrize("client", [False], indirect=True) # loose validation +def test_response_parse_expect_model_union_non_json_content(client: Gcore) -> None: + response = APIResponse( + raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = response.parse(to=cast(Any, Union[CustomModel, OtherModel])) + assert isinstance(obj, str) + assert obj == "foo" + + +@pytest.mark.asyncio +@pytest.mark.parametrize("async_client", [False], indirect=True) # loose validation +async def test_async_response_parse_expect_model_union_non_json_content(async_client: AsyncGcore) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}), + client=async_client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = await response.parse(to=cast(Any, Union[CustomModel, OtherModel])) + assert isinstance(obj, str) + assert obj == "foo" diff --git a/tests/test_streaming.py b/tests/test_streaming.py new file mode 100644 index 00000000..54412add --- /dev/null +++ b/tests/test_streaming.py @@ -0,0 +1,248 @@ +from __future__ import annotations + +from typing import Iterator, AsyncIterator + +import httpx +import pytest + +from gcore import Gcore, AsyncGcore +from gcore._streaming import Stream, AsyncStream, ServerSentEvent + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_basic(sync: bool, client: Gcore, async_client: AsyncGcore) -> None: + def body() -> Iterator[bytes]: + yield b"event: completion\n" + yield b'data: {"foo":true}\n' + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "completion" + assert sse.json() == {"foo": True} + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_data_missing_event(sync: bool, client: Gcore, async_client: AsyncGcore) -> None: + def body() -> Iterator[bytes]: + yield b'data: {"foo":true}\n' + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"foo": True} + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_event_missing_data(sync: bool, client: Gcore, async_client: AsyncGcore) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.data == "" + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multiple_events(sync: bool, client: Gcore, async_client: AsyncGcore) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b"\n" + yield b"event: completion\n" + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.data == "" + + sse = await iter_next(iterator) + assert sse.event == "completion" + assert sse.data == "" + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multiple_events_with_data(sync: bool, client: Gcore, async_client: AsyncGcore) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b'data: {"foo":true}\n' + yield b"\n" + yield b"event: completion\n" + yield b'data: {"bar":false}\n' + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.json() == {"foo": True} + + sse = await iter_next(iterator) + assert sse.event == "completion" + assert sse.json() == {"bar": False} + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multiple_data_lines_with_empty_line(sync: bool, client: Gcore, async_client: AsyncGcore) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b"data: {\n" + yield b'data: "foo":\n' + yield b"data: \n" + yield b"data:\n" + yield b"data: true}\n" + yield b"\n\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.json() == {"foo": True} + assert sse.data == '{\n"foo":\n\n\ntrue}' + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_data_json_escaped_double_new_line(sync: bool, client: Gcore, async_client: AsyncGcore) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b'data: {"foo": "my long\\n\\ncontent"}' + yield b"\n\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.json() == {"foo": "my long\n\ncontent"} + + await assert_empty_iter(iterator) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multiple_data_lines(sync: bool, client: Gcore, async_client: AsyncGcore) -> None: + def body() -> Iterator[bytes]: + yield b"event: ping\n" + yield b"data: {\n" + yield b'data: "foo":\n' + yield b"data: true}\n" + yield b"\n\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event == "ping" + assert sse.json() == {"foo": True} + + await assert_empty_iter(iterator) + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_special_new_line_character( + sync: bool, + client: Gcore, + async_client: AsyncGcore, +) -> None: + def body() -> Iterator[bytes]: + yield b'data: {"content":" culpa"}\n' + yield b"\n" + yield b'data: {"content":" \xe2\x80\xa8"}\n' + yield b"\n" + yield b'data: {"content":"foo"}\n' + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"content": " culpa"} + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"content": " 
"} + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"content": "foo"} + + await assert_empty_iter(iterator) + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +async def test_multi_byte_character_multiple_chunks( + sync: bool, + client: Gcore, + async_client: AsyncGcore, +) -> None: + def body() -> Iterator[bytes]: + yield b'data: {"content":"' + # bytes taken from the string 'известни' and arbitrarily split + # so that some multi-byte characters span multiple chunks + yield b"\xd0" + yield b"\xb8\xd0\xb7\xd0" + yield b"\xb2\xd0\xb5\xd1\x81\xd1\x82\xd0\xbd\xd0\xb8" + yield b'"}\n' + yield b"\n" + + iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) + + sse = await iter_next(iterator) + assert sse.event is None + assert sse.json() == {"content": "известни"} + + +async def to_aiter(iter: Iterator[bytes]) -> AsyncIterator[bytes]: + for chunk in iter: + yield chunk + + +async def iter_next(iter: Iterator[ServerSentEvent] | AsyncIterator[ServerSentEvent]) -> ServerSentEvent: + if isinstance(iter, AsyncIterator): + return await iter.__anext__() + + return next(iter) + + +async def assert_empty_iter(iter: Iterator[ServerSentEvent] | AsyncIterator[ServerSentEvent]) -> None: + with pytest.raises((StopAsyncIteration, RuntimeError)): + await iter_next(iter) + + +def make_event_iterator( + content: Iterator[bytes], + *, + sync: bool, + client: Gcore, + async_client: AsyncGcore, +) -> Iterator[ServerSentEvent] | AsyncIterator[ServerSentEvent]: + if sync: + return Stream(cast_to=object, client=client, response=httpx.Response(200, content=content))._iter_events() + + return AsyncStream( + cast_to=object, client=async_client, response=httpx.Response(200, content=to_aiter(content)) + )._iter_events() diff --git a/tests/test_transform.py b/tests/test_transform.py new file mode 100644 index 00000000..f66c5ae2 --- /dev/null +++ b/tests/test_transform.py @@ -0,0 +1,460 @@ +from __future__ import annotations + +import io +import pathlib +from typing import Any, Dict, List, Union, TypeVar, Iterable, Optional, cast +from datetime import date, datetime +from typing_extensions import Required, Annotated, TypedDict + +import pytest + +from gcore._types import Base64FileInput, omit, not_given +from gcore._utils import ( + PropertyInfo, + transform as _transform, + parse_datetime, + async_transform as _async_transform, +) +from gcore._compat import PYDANTIC_V1 +from gcore._models import BaseModel + +_T = TypeVar("_T") + +SAMPLE_FILE_PATH = pathlib.Path(__file__).parent.joinpath("sample_file.txt") + + +async def transform( + data: _T, + expected_type: object, + use_async: bool, +) -> _T: + if use_async: + return await _async_transform(data, expected_type=expected_type) + + return _transform(data, expected_type=expected_type) + + +parametrize = pytest.mark.parametrize("use_async", [False, True], ids=["sync", "async"]) + + +class Foo1(TypedDict): + foo_bar: Annotated[str, PropertyInfo(alias="fooBar")] + + +@parametrize +@pytest.mark.asyncio +async def test_top_level_alias(use_async: bool) -> None: + assert await transform({"foo_bar": "hello"}, expected_type=Foo1, use_async=use_async) == {"fooBar": "hello"} + + +class Foo2(TypedDict): + bar: Bar2 + + +class Bar2(TypedDict): + this_thing: Annotated[int, PropertyInfo(alias="this__thing")] + baz: Annotated[Baz2, PropertyInfo(alias="Baz")] + + +class Baz2(TypedDict): + my_baz: Annotated[str, PropertyInfo(alias="myBaz")] + + +@parametrize +@pytest.mark.asyncio +async def test_recursive_typeddict(use_async: bool) -> None: + assert await transform({"bar": {"this_thing": 1}}, Foo2, use_async) == {"bar": {"this__thing": 1}} + assert await transform({"bar": {"baz": {"my_baz": "foo"}}}, Foo2, use_async) == {"bar": {"Baz": {"myBaz": "foo"}}} + + +class Foo3(TypedDict): + things: List[Bar3] + + +class Bar3(TypedDict): + my_field: Annotated[str, PropertyInfo(alias="myField")] + + +@parametrize +@pytest.mark.asyncio +async def test_list_of_typeddict(use_async: bool) -> None: + result = await transform({"things": [{"my_field": "foo"}, {"my_field": "foo2"}]}, Foo3, use_async) + assert result == {"things": [{"myField": "foo"}, {"myField": "foo2"}]} + + +class Foo4(TypedDict): + foo: Union[Bar4, Baz4] + + +class Bar4(TypedDict): + foo_bar: Annotated[str, PropertyInfo(alias="fooBar")] + + +class Baz4(TypedDict): + foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] + + +@parametrize +@pytest.mark.asyncio +async def test_union_of_typeddict(use_async: bool) -> None: + assert await transform({"foo": {"foo_bar": "bar"}}, Foo4, use_async) == {"foo": {"fooBar": "bar"}} + assert await transform({"foo": {"foo_baz": "baz"}}, Foo4, use_async) == {"foo": {"fooBaz": "baz"}} + assert await transform({"foo": {"foo_baz": "baz", "foo_bar": "bar"}}, Foo4, use_async) == { + "foo": {"fooBaz": "baz", "fooBar": "bar"} + } + + +class Foo5(TypedDict): + foo: Annotated[Union[Bar4, List[Baz4]], PropertyInfo(alias="FOO")] + + +class Bar5(TypedDict): + foo_bar: Annotated[str, PropertyInfo(alias="fooBar")] + + +class Baz5(TypedDict): + foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] + + +@parametrize +@pytest.mark.asyncio +async def test_union_of_list(use_async: bool) -> None: + assert await transform({"foo": {"foo_bar": "bar"}}, Foo5, use_async) == {"FOO": {"fooBar": "bar"}} + assert await transform( + { + "foo": [ + {"foo_baz": "baz"}, + {"foo_baz": "baz"}, + ] + }, + Foo5, + use_async, + ) == {"FOO": [{"fooBaz": "baz"}, {"fooBaz": "baz"}]} + + +class Foo6(TypedDict): + bar: Annotated[str, PropertyInfo(alias="Bar")] + + +@parametrize +@pytest.mark.asyncio +async def test_includes_unknown_keys(use_async: bool) -> None: + assert await transform({"bar": "bar", "baz_": {"FOO": 1}}, Foo6, use_async) == { + "Bar": "bar", + "baz_": {"FOO": 1}, + } + + +class Foo7(TypedDict): + bar: Annotated[List[Bar7], PropertyInfo(alias="bAr")] + foo: Bar7 + + +class Bar7(TypedDict): + foo: str + + +@parametrize +@pytest.mark.asyncio +async def test_ignores_invalid_input(use_async: bool) -> None: + assert await transform({"bar": ""}, Foo7, use_async) == {"bAr": ""} + assert await transform({"foo": ""}, Foo7, use_async) == {"foo": ""} + + +class DatetimeDict(TypedDict, total=False): + foo: Annotated[datetime, PropertyInfo(format="iso8601")] + + bar: Annotated[Optional[datetime], PropertyInfo(format="iso8601")] + + required: Required[Annotated[Optional[datetime], PropertyInfo(format="iso8601")]] + + list_: Required[Annotated[Optional[List[datetime]], PropertyInfo(format="iso8601")]] + + union: Annotated[Union[int, datetime], PropertyInfo(format="iso8601")] + + +class DateDict(TypedDict, total=False): + foo: Annotated[date, PropertyInfo(format="iso8601")] + + +class DatetimeModel(BaseModel): + foo: datetime + + +class DateModel(BaseModel): + foo: Optional[date] + + +@parametrize +@pytest.mark.asyncio +async def test_iso8601_format(use_async: bool) -> None: + dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") + tz = "+00:00" if PYDANTIC_V1 else "Z" + assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692+00:00"} # type: ignore[comparison-overlap] + assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692" + tz} # type: ignore[comparison-overlap] + + dt = dt.replace(tzinfo=None) + assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692"} # type: ignore[comparison-overlap] + assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692"} # type: ignore[comparison-overlap] + + assert await transform({"foo": None}, DateDict, use_async) == {"foo": None} # type: ignore[comparison-overlap] + assert await transform(DateModel(foo=None), Any, use_async) == {"foo": None} # type: ignore + assert await transform({"foo": date.fromisoformat("2023-02-23")}, DateDict, use_async) == {"foo": "2023-02-23"} # type: ignore[comparison-overlap] + assert await transform(DateModel(foo=date.fromisoformat("2023-02-23")), DateDict, use_async) == { + "foo": "2023-02-23" + } # type: ignore[comparison-overlap] + + +@parametrize +@pytest.mark.asyncio +async def test_optional_iso8601_format(use_async: bool) -> None: + dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") + assert await transform({"bar": dt}, DatetimeDict, use_async) == {"bar": "2023-02-23T14:16:36.337692+00:00"} # type: ignore[comparison-overlap] + + assert await transform({"bar": None}, DatetimeDict, use_async) == {"bar": None} + + +@parametrize +@pytest.mark.asyncio +async def test_required_iso8601_format(use_async: bool) -> None: + dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") + assert await transform({"required": dt}, DatetimeDict, use_async) == { + "required": "2023-02-23T14:16:36.337692+00:00" + } # type: ignore[comparison-overlap] + + assert await transform({"required": None}, DatetimeDict, use_async) == {"required": None} + + +@parametrize +@pytest.mark.asyncio +async def test_union_datetime(use_async: bool) -> None: + dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") + assert await transform({"union": dt}, DatetimeDict, use_async) == { # type: ignore[comparison-overlap] + "union": "2023-02-23T14:16:36.337692+00:00" + } + + assert await transform({"union": "foo"}, DatetimeDict, use_async) == {"union": "foo"} + + +@parametrize +@pytest.mark.asyncio +async def test_nested_list_iso6801_format(use_async: bool) -> None: + dt1 = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") + dt2 = parse_datetime("2022-01-15T06:34:23Z") + assert await transform({"list_": [dt1, dt2]}, DatetimeDict, use_async) == { # type: ignore[comparison-overlap] + "list_": ["2023-02-23T14:16:36.337692+00:00", "2022-01-15T06:34:23+00:00"] + } + + +@parametrize +@pytest.mark.asyncio +async def test_datetime_custom_format(use_async: bool) -> None: + dt = parse_datetime("2022-01-15T06:34:23Z") + + result = await transform(dt, Annotated[datetime, PropertyInfo(format="custom", format_template="%H")], use_async) + assert result == "06" # type: ignore[comparison-overlap] + + +class DateDictWithRequiredAlias(TypedDict, total=False): + required_prop: Required[Annotated[date, PropertyInfo(format="iso8601", alias="prop")]] + + +@parametrize +@pytest.mark.asyncio +async def test_datetime_with_alias(use_async: bool) -> None: + assert await transform({"required_prop": None}, DateDictWithRequiredAlias, use_async) == {"prop": None} # type: ignore[comparison-overlap] + assert await transform( + {"required_prop": date.fromisoformat("2023-02-23")}, DateDictWithRequiredAlias, use_async + ) == {"prop": "2023-02-23"} # type: ignore[comparison-overlap] + + +class MyModel(BaseModel): + foo: str + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_model_to_dictionary(use_async: bool) -> None: + assert cast(Any, await transform(MyModel(foo="hi!"), Any, use_async)) == {"foo": "hi!"} + assert cast(Any, await transform(MyModel.construct(foo="hi!"), Any, use_async)) == {"foo": "hi!"} + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_empty_model(use_async: bool) -> None: + assert cast(Any, await transform(MyModel.construct(), Any, use_async)) == {} + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_unknown_field(use_async: bool) -> None: + assert cast(Any, await transform(MyModel.construct(my_untyped_field=True), Any, use_async)) == { + "my_untyped_field": True + } + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_mismatched_types(use_async: bool) -> None: + model = MyModel.construct(foo=True) + if PYDANTIC_V1: + params = await transform(model, Any, use_async) + else: + with pytest.warns(UserWarning): + params = await transform(model, Any, use_async) + assert cast(Any, params) == {"foo": True} + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_mismatched_object_type(use_async: bool) -> None: + model = MyModel.construct(foo=MyModel.construct(hello="world")) + if PYDANTIC_V1: + params = await transform(model, Any, use_async) + else: + with pytest.warns(UserWarning): + params = await transform(model, Any, use_async) + assert cast(Any, params) == {"foo": {"hello": "world"}} + + +class ModelNestedObjects(BaseModel): + nested: MyModel + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_nested_objects(use_async: bool) -> None: + model = ModelNestedObjects.construct(nested={"foo": "stainless"}) + assert isinstance(model.nested, MyModel) + assert cast(Any, await transform(model, Any, use_async)) == {"nested": {"foo": "stainless"}} + + +class ModelWithDefaultField(BaseModel): + foo: str + with_none_default: Union[str, None] = None + with_str_default: str = "foo" + + +@parametrize +@pytest.mark.asyncio +async def test_pydantic_default_field(use_async: bool) -> None: + # should be excluded when defaults are used + model = ModelWithDefaultField.construct() + assert model.with_none_default is None + assert model.with_str_default == "foo" + assert cast(Any, await transform(model, Any, use_async)) == {} + + # should be included when the default value is explicitly given + model = ModelWithDefaultField.construct(with_none_default=None, with_str_default="foo") + assert model.with_none_default is None + assert model.with_str_default == "foo" + assert cast(Any, await transform(model, Any, use_async)) == {"with_none_default": None, "with_str_default": "foo"} + + # should be included when a non-default value is explicitly given + model = ModelWithDefaultField.construct(with_none_default="bar", with_str_default="baz") + assert model.with_none_default == "bar" + assert model.with_str_default == "baz" + assert cast(Any, await transform(model, Any, use_async)) == {"with_none_default": "bar", "with_str_default": "baz"} + + +class TypedDictIterableUnion(TypedDict): + foo: Annotated[Union[Bar8, Iterable[Baz8]], PropertyInfo(alias="FOO")] + + +class Bar8(TypedDict): + foo_bar: Annotated[str, PropertyInfo(alias="fooBar")] + + +class Baz8(TypedDict): + foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] + + +@parametrize +@pytest.mark.asyncio +async def test_iterable_of_dictionaries(use_async: bool) -> None: + assert await transform({"foo": [{"foo_baz": "bar"}]}, TypedDictIterableUnion, use_async) == { + "FOO": [{"fooBaz": "bar"}] + } + assert cast(Any, await transform({"foo": ({"foo_baz": "bar"},)}, TypedDictIterableUnion, use_async)) == { + "FOO": [{"fooBaz": "bar"}] + } + + def my_iter() -> Iterable[Baz8]: + yield {"foo_baz": "hello"} + yield {"foo_baz": "world"} + + assert await transform({"foo": my_iter()}, TypedDictIterableUnion, use_async) == { + "FOO": [{"fooBaz": "hello"}, {"fooBaz": "world"}] + } + + +@parametrize +@pytest.mark.asyncio +async def test_dictionary_items(use_async: bool) -> None: + class DictItems(TypedDict): + foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] + + assert await transform({"foo": {"foo_baz": "bar"}}, Dict[str, DictItems], use_async) == {"foo": {"fooBaz": "bar"}} + + +class TypedDictIterableUnionStr(TypedDict): + foo: Annotated[Union[str, Iterable[Baz8]], PropertyInfo(alias="FOO")] + + +@parametrize +@pytest.mark.asyncio +async def test_iterable_union_str(use_async: bool) -> None: + assert await transform({"foo": "bar"}, TypedDictIterableUnionStr, use_async) == {"FOO": "bar"} + assert cast(Any, await transform(iter([{"foo_baz": "bar"}]), Union[str, Iterable[Baz8]], use_async)) == [ + {"fooBaz": "bar"} + ] + + +class TypedDictBase64Input(TypedDict): + foo: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] + + +@parametrize +@pytest.mark.asyncio +async def test_base64_file_input(use_async: bool) -> None: + # strings are left as-is + assert await transform({"foo": "bar"}, TypedDictBase64Input, use_async) == {"foo": "bar"} + + # pathlib.Path is automatically converted to base64 + assert await transform({"foo": SAMPLE_FILE_PATH}, TypedDictBase64Input, use_async) == { + "foo": "SGVsbG8sIHdvcmxkIQo=" + } # type: ignore[comparison-overlap] + + # io instances are automatically converted to base64 + assert await transform({"foo": io.StringIO("Hello, world!")}, TypedDictBase64Input, use_async) == { + "foo": "SGVsbG8sIHdvcmxkIQ==" + } # type: ignore[comparison-overlap] + assert await transform({"foo": io.BytesIO(b"Hello, world!")}, TypedDictBase64Input, use_async) == { + "foo": "SGVsbG8sIHdvcmxkIQ==" + } # type: ignore[comparison-overlap] + + +@parametrize +@pytest.mark.asyncio +async def test_transform_skipping(use_async: bool) -> None: + # lists of ints are left as-is + data = [1, 2, 3] + assert await transform(data, List[int], use_async) is data + + # iterables of ints are converted to a list + data = iter([1, 2, 3]) + assert await transform(data, Iterable[int], use_async) == [1, 2, 3] + + +@parametrize +@pytest.mark.asyncio +async def test_strips_notgiven(use_async: bool) -> None: + assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} + assert await transform({"foo_bar": not_given}, Foo1, use_async) == {} + + +@parametrize +@pytest.mark.asyncio +async def test_strips_omit(use_async: bool) -> None: + assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} + assert await transform({"foo_bar": omit}, Foo1, use_async) == {} diff --git a/tests/test_utils/test_datetime_parse.py b/tests/test_utils/test_datetime_parse.py new file mode 100644 index 00000000..2762807e --- /dev/null +++ b/tests/test_utils/test_datetime_parse.py @@ -0,0 +1,110 @@ +""" +Copied from https://github.com/pydantic/pydantic/blob/v1.10.22/tests/test_datetime_parse.py +with modifications so it works without pydantic v1 imports. +""" + +from typing import Type, Union +from datetime import date, datetime, timezone, timedelta + +import pytest + +from gcore._utils import parse_date, parse_datetime + + +def create_tz(minutes: int) -> timezone: + return timezone(timedelta(minutes=minutes)) + + +@pytest.mark.parametrize( + "value,result", + [ + # Valid inputs + ("1494012444.883309", date(2017, 5, 5)), + (b"1494012444.883309", date(2017, 5, 5)), + (1_494_012_444.883_309, date(2017, 5, 5)), + ("1494012444", date(2017, 5, 5)), + (1_494_012_444, date(2017, 5, 5)), + (0, date(1970, 1, 1)), + ("2012-04-23", date(2012, 4, 23)), + (b"2012-04-23", date(2012, 4, 23)), + ("2012-4-9", date(2012, 4, 9)), + (date(2012, 4, 9), date(2012, 4, 9)), + (datetime(2012, 4, 9, 12, 15), date(2012, 4, 9)), + # Invalid inputs + ("x20120423", ValueError), + ("2012-04-56", ValueError), + (19_999_999_999, date(2603, 10, 11)), # just before watershed + (20_000_000_001, date(1970, 8, 20)), # just after watershed + (1_549_316_052, date(2019, 2, 4)), # nowish in s + (1_549_316_052_104, date(2019, 2, 4)), # nowish in ms + (1_549_316_052_104_324, date(2019, 2, 4)), # nowish in μs + (1_549_316_052_104_324_096, date(2019, 2, 4)), # nowish in ns + ("infinity", date(9999, 12, 31)), + ("inf", date(9999, 12, 31)), + (float("inf"), date(9999, 12, 31)), + ("infinity ", date(9999, 12, 31)), + (int("1" + "0" * 100), date(9999, 12, 31)), + (1e1000, date(9999, 12, 31)), + ("-infinity", date(1, 1, 1)), + ("-inf", date(1, 1, 1)), + ("nan", ValueError), + ], +) +def test_date_parsing(value: Union[str, bytes, int, float], result: Union[date, Type[Exception]]) -> None: + if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance] + with pytest.raises(result): + parse_date(value) + else: + assert parse_date(value) == result + + +@pytest.mark.parametrize( + "value,result", + [ + # Valid inputs + # values in seconds + ("1494012444.883309", datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)), + (1_494_012_444.883_309, datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)), + ("1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + (b"1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + (1_494_012_444, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + # values in ms + ("1494012444000.883309", datetime(2017, 5, 5, 19, 27, 24, 883, tzinfo=timezone.utc)), + ("-1494012444000.883309", datetime(1922, 8, 29, 4, 32, 35, 999117, tzinfo=timezone.utc)), + (1_494_012_444_000, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + ("2012-04-23T09:15:00", datetime(2012, 4, 23, 9, 15)), + ("2012-4-9 4:8:16", datetime(2012, 4, 9, 4, 8, 16)), + ("2012-04-23T09:15:00Z", datetime(2012, 4, 23, 9, 15, 0, 0, timezone.utc)), + ("2012-4-9 4:8:16-0320", datetime(2012, 4, 9, 4, 8, 16, 0, create_tz(-200))), + ("2012-04-23T10:20:30.400+02:30", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(150))), + ("2012-04-23T10:20:30.400+02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(120))), + ("2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))), + (b"2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))), + (datetime(2017, 5, 5), datetime(2017, 5, 5)), + (0, datetime(1970, 1, 1, 0, 0, 0, tzinfo=timezone.utc)), + # Invalid inputs + ("x20120423091500", ValueError), + ("2012-04-56T09:15:90", ValueError), + ("2012-04-23T11:05:00-25:00", ValueError), + (19_999_999_999, datetime(2603, 10, 11, 11, 33, 19, tzinfo=timezone.utc)), # just before watershed + (20_000_000_001, datetime(1970, 8, 20, 11, 33, 20, 1000, tzinfo=timezone.utc)), # just after watershed + (1_549_316_052, datetime(2019, 2, 4, 21, 34, 12, 0, tzinfo=timezone.utc)), # nowish in s + (1_549_316_052_104, datetime(2019, 2, 4, 21, 34, 12, 104_000, tzinfo=timezone.utc)), # nowish in ms + (1_549_316_052_104_324, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in μs + (1_549_316_052_104_324_096, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in ns + ("infinity", datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("inf", datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("inf ", datetime(9999, 12, 31, 23, 59, 59, 999999)), + (1e50, datetime(9999, 12, 31, 23, 59, 59, 999999)), + (float("inf"), datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("-infinity", datetime(1, 1, 1, 0, 0)), + ("-inf", datetime(1, 1, 1, 0, 0)), + ("nan", ValueError), + ], +) +def test_datetime_parsing(value: Union[str, bytes, int, float], result: Union[datetime, Type[Exception]]) -> None: + if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance] + with pytest.raises(result): + parse_datetime(value) + else: + assert parse_datetime(value) == result diff --git a/tests/test_utils/test_json.py b/tests/test_utils/test_json.py new file mode 100644 index 00000000..9e4ec0e5 --- /dev/null +++ b/tests/test_utils/test_json.py @@ -0,0 +1,126 @@ +from __future__ import annotations + +import datetime +from typing import Union + +import pydantic + +from gcore import _compat +from gcore._utils._json import openapi_dumps + + +class TestOpenapiDumps: + def test_basic(self) -> None: + data = {"key": "value", "number": 42} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"key":"value","number":42}' + + def test_datetime_serialization(self) -> None: + dt = datetime.datetime(2023, 1, 1, 12, 0, 0) + data = {"datetime": dt} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"datetime":"2023-01-01T12:00:00"}' + + def test_pydantic_model_serialization(self) -> None: + class User(pydantic.BaseModel): + first_name: str + last_name: str + age: int + + model_instance = User(first_name="John", last_name="Kramer", age=83) + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"first_name":"John","last_name":"Kramer","age":83}}' + + def test_pydantic_model_with_default_values(self) -> None: + class User(pydantic.BaseModel): + name: str + role: str = "user" + active: bool = True + score: int = 0 + + model_instance = User(name="Alice") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Alice"}}' + + def test_pydantic_model_with_default_values_overridden(self) -> None: + class User(pydantic.BaseModel): + name: str + role: str = "user" + active: bool = True + + model_instance = User(name="Bob", role="admin", active=False) + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Bob","role":"admin","active":false}}' + + def test_pydantic_model_with_alias(self) -> None: + class User(pydantic.BaseModel): + first_name: str = pydantic.Field(alias="firstName") + last_name: str = pydantic.Field(alias="lastName") + + model_instance = User(firstName="John", lastName="Doe") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"firstName":"John","lastName":"Doe"}}' + + def test_pydantic_model_with_alias_and_default(self) -> None: + class User(pydantic.BaseModel): + user_name: str = pydantic.Field(alias="userName") + user_role: str = pydantic.Field(default="member", alias="userRole") + is_active: bool = pydantic.Field(default=True, alias="isActive") + + model_instance = User(userName="charlie") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"userName":"charlie"}}' + + model_with_overrides = User(userName="diana", userRole="admin", isActive=False) + data = {"model": model_with_overrides} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"userName":"diana","userRole":"admin","isActive":false}}' + + def test_pydantic_model_with_nested_models_and_defaults(self) -> None: + class Address(pydantic.BaseModel): + street: str + city: str = "Unknown" + + class User(pydantic.BaseModel): + name: str + address: Address + verified: bool = False + + if _compat.PYDANTIC_V1: + # to handle forward references in Pydantic v1 + User.update_forward_refs(**locals()) # type: ignore[reportDeprecated] + + address = Address(street="123 Main St") + user = User(name="Diana", address=address) + data = {"user": user} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"user":{"name":"Diana","address":{"street":"123 Main St"}}}' + + address_with_city = Address(street="456 Oak Ave", city="Boston") + user_verified = User(name="Eve", address=address_with_city, verified=True) + data = {"user": user_verified} + json_bytes = openapi_dumps(data) + assert ( + json_bytes == b'{"user":{"name":"Eve","address":{"street":"456 Oak Ave","city":"Boston"},"verified":true}}' + ) + + def test_pydantic_model_with_optional_fields(self) -> None: + class User(pydantic.BaseModel): + name: str + email: Union[str, None] + phone: Union[str, None] + + model_with_none = User(name="Eve", email=None, phone=None) + data = {"model": model_with_none} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Eve","email":null,"phone":null}}' + + model_with_values = User(name="Frank", email="frank@example.com", phone=None) + data = {"model": model_with_values} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Frank","email":"frank@example.com","phone":null}}' diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py new file mode 100644 index 00000000..f7b2b9ee --- /dev/null +++ b/tests/test_utils/test_proxy.py @@ -0,0 +1,34 @@ +import operator +from typing import Any +from typing_extensions import override + +from gcore._utils import LazyProxy + + +class RecursiveLazyProxy(LazyProxy[Any]): + @override + def __load__(self) -> Any: + return self + + def __call__(self, *_args: Any, **_kwds: Any) -> Any: + raise RuntimeError("This should never be called!") + + +def test_recursive_proxy() -> None: + proxy = RecursiveLazyProxy() + assert repr(proxy) == "RecursiveLazyProxy" + assert str(proxy) == "RecursiveLazyProxy" + assert dir(proxy) == [] + assert type(proxy).__name__ == "RecursiveLazyProxy" + assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy" + + +def test_isinstance_does_not_error() -> None: + class AlwaysErrorProxy(LazyProxy[Any]): + @override + def __load__(self) -> Any: + raise RuntimeError("Mocking missing dependency") + + proxy = AlwaysErrorProxy() + assert not isinstance(proxy, dict) + assert isinstance(proxy, LazyProxy) diff --git a/tests/test_utils/test_typing.py b/tests/test_utils/test_typing.py new file mode 100644 index 00000000..b22bcc80 --- /dev/null +++ b/tests/test_utils/test_typing.py @@ -0,0 +1,73 @@ +from __future__ import annotations + +from typing import Generic, TypeVar, cast + +from gcore._utils import extract_type_var_from_base + +_T = TypeVar("_T") +_T2 = TypeVar("_T2") +_T3 = TypeVar("_T3") + + +class BaseGeneric(Generic[_T]): ... + + +class SubclassGeneric(BaseGeneric[_T]): ... + + +class BaseGenericMultipleTypeArgs(Generic[_T, _T2, _T3]): ... + + +class SubclassGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T, _T2, _T3]): ... + + +class SubclassDifferentOrderGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T2, _T, _T3]): ... + + +def test_extract_type_var() -> None: + assert ( + extract_type_var_from_base( + BaseGeneric[int], + index=0, + generic_bases=cast("tuple[type, ...]", (BaseGeneric,)), + ) + == int + ) + + +def test_extract_type_var_generic_subclass() -> None: + assert ( + extract_type_var_from_base( + SubclassGeneric[int], + index=0, + generic_bases=cast("tuple[type, ...]", (BaseGeneric,)), + ) + == int + ) + + +def test_extract_type_var_multiple() -> None: + typ = BaseGenericMultipleTypeArgs[int, str, None] + + generic_bases = cast("tuple[type, ...]", (BaseGenericMultipleTypeArgs,)) + assert extract_type_var_from_base(typ, index=0, generic_bases=generic_bases) == int + assert extract_type_var_from_base(typ, index=1, generic_bases=generic_bases) == str + assert extract_type_var_from_base(typ, index=2, generic_bases=generic_bases) == type(None) + + +def test_extract_type_var_generic_subclass_multiple() -> None: + typ = SubclassGenericMultipleTypeArgs[int, str, None] + + generic_bases = cast("tuple[type, ...]", (BaseGenericMultipleTypeArgs,)) + assert extract_type_var_from_base(typ, index=0, generic_bases=generic_bases) == int + assert extract_type_var_from_base(typ, index=1, generic_bases=generic_bases) == str + assert extract_type_var_from_base(typ, index=2, generic_bases=generic_bases) == type(None) + + +def test_extract_type_var_generic_subclass_different_ordering_multiple() -> None: + typ = SubclassDifferentOrderGenericMultipleTypeArgs[int, str, None] + + generic_bases = cast("tuple[type, ...]", (BaseGenericMultipleTypeArgs,)) + assert extract_type_var_from_base(typ, index=0, generic_bases=generic_bases) == int + assert extract_type_var_from_base(typ, index=1, generic_bases=generic_bases) == str + assert extract_type_var_from_base(typ, index=2, generic_bases=generic_bases) == type(None) diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 00000000..a391741f --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,167 @@ +from __future__ import annotations + +import os +import inspect +import traceback +import contextlib +from typing import Any, TypeVar, Iterator, Sequence, cast +from datetime import date, datetime +from typing_extensions import Literal, get_args, get_origin, assert_type + +from gcore._types import Omit, NoneType +from gcore._utils import ( + is_dict, + is_list, + is_list_type, + is_union_type, + extract_type_arg, + is_sequence_type, + is_annotated_type, + is_type_alias_type, +) +from gcore._compat import PYDANTIC_V1, field_outer_type, get_model_fields +from gcore._models import BaseModel + +BaseModelT = TypeVar("BaseModelT", bound=BaseModel) + + +def assert_matches_model(model: type[BaseModelT], value: BaseModelT, *, path: list[str]) -> bool: + for name, field in get_model_fields(model).items(): + field_value = getattr(value, name) + if PYDANTIC_V1: + # in v1 nullability was structured differently + # https://docs.pydantic.dev/2.0/migration/#required-optional-and-nullable-fields + allow_none = getattr(field, "allow_none", False) + else: + allow_none = False + + assert_matches_type( + field_outer_type(field), + field_value, + path=[*path, name], + allow_none=allow_none, + ) + + return True + + +# Note: the `path` argument is only used to improve error messages when `--showlocals` is used +def assert_matches_type( + type_: Any, + value: object, + *, + path: list[str], + allow_none: bool = False, +) -> None: + if is_type_alias_type(type_): + type_ = type_.__value__ + + # unwrap `Annotated[T, ...]` -> `T` + if is_annotated_type(type_): + type_ = extract_type_arg(type_, 0) + + if allow_none and value is None: + return + + if type_ is None or type_ is NoneType: + assert value is None + return + + origin = get_origin(type_) or type_ + + if is_list_type(type_): + return _assert_list_type(type_, value) + + if is_sequence_type(type_): + assert isinstance(value, Sequence) + inner_type = get_args(type_)[0] + for entry in value: # type: ignore + assert_type(inner_type, entry) # type: ignore + return + + if origin == str: + assert isinstance(value, str) + elif origin == int: + assert isinstance(value, int) + elif origin == bool: + assert isinstance(value, bool) + elif origin == float: + assert isinstance(value, float) + elif origin == bytes: + assert isinstance(value, bytes) + elif origin == datetime: + assert isinstance(value, datetime) + elif origin == date: + assert isinstance(value, date) + elif origin == object: + # nothing to do here, the expected type is unknown + pass + elif origin == Literal: + assert value in get_args(type_) + elif origin == dict: + assert is_dict(value) + + args = get_args(type_) + key_type = args[0] + items_type = args[1] + + for key, item in value.items(): + assert_matches_type(key_type, key, path=[*path, ""]) + assert_matches_type(items_type, item, path=[*path, ""]) + elif is_union_type(type_): + variants = get_args(type_) + + try: + none_index = variants.index(type(None)) + except ValueError: + pass + else: + # special case Optional[T] for better error messages + if len(variants) == 2: + if value is None: + # valid + return + + return assert_matches_type(type_=variants[not none_index], value=value, path=path) + + for i, variant in enumerate(variants): + try: + assert_matches_type(variant, value, path=[*path, f"variant {i}"]) + return + except AssertionError: + traceback.print_exc() + continue + + raise AssertionError("Did not match any variants") + elif issubclass(origin, BaseModel): + assert isinstance(value, type_) + assert assert_matches_model(type_, cast(Any, value), path=path) + elif inspect.isclass(origin) and origin.__name__ == "HttpxBinaryResponseContent": + assert value.__class__.__name__ == "HttpxBinaryResponseContent" + else: + assert None, f"Unhandled field type: {type_}" + + +def _assert_list_type(type_: type[object], value: object) -> None: + assert is_list(value) + + inner_type = get_args(type_)[0] + for entry in value: + assert_type(inner_type, entry) # type: ignore + + +@contextlib.contextmanager +def update_env(**new_env: str | Omit) -> Iterator[None]: + old = os.environ.copy() + + try: + for name, value in new_env.items(): + if isinstance(value, Omit): + os.environ.pop(name, None) + else: + os.environ[name] = value + + yield None + finally: + os.environ.clear() + os.environ.update(old)